home *** CD-ROM | disk | FTP | other *** search
/ Czech Logic, Card & Gambling Games / Logické hry.iso / hry / Piskvorky / source / PISKVORK.cpp < prev    next >
C/C++ Source or Header  |  2006-05-25  |  71KB  |  2,730 lines

  1. /*
  2.   (C) 2000-2006  Petr Lastovicka
  3.  
  4.   contents of this file are subject to the Reciprocal Public License ("RPL")
  5. */
  6. //-----------------------------------------------------------------
  7. #ifndef _WIN32_IE
  8.   #define _WIN32_IE 0x0400
  9. #endif
  10. #include <windows.h>
  11. #pragma hdrstop
  12. #include <shlobj.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #include <time.h>
  18. #include "lang.h"
  19. #include "piskvork.h"
  20. //-----------------------------------------------------------------
  21. /*
  22. USERC("Piskvork.rc");
  23. USEUNIT("nettur.cpp");
  24. USEUNIT("protocol.cpp");
  25. USEUNIT("game.cpp");
  26. USEUNIT("lang.cpp");
  27. USEUNIT("netgame.cpp");
  28. */
  29. //-----------------------------------------------------------------
  30.  
  31. //toolbar buttons
  32. const int Ntool=18;
  33. const TBBUTTON tbb[]={
  34.  {6,101,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  35.  {0,106,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  36.  {1,107,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  37.  {0,0,0,TBSTYLE_SEP,{0},0},
  38.  {10,104,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  39.  {12,406,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  40.  {14,219,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  41.  {13,221,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  42.  {0,0,0,TBSTYLE_SEP,{0},0},
  43.  {7,205,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  44.  {3,210,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  45.  {5,201,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  46.  {4,202,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  47.  {2,211,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  48.  {11,208,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  49.  {0,0,0,TBSTYLE_SEP,{0},0},
  50.  {8,301,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  51.  {9,302,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  52.  {21,303,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  53.  {18,304,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  54.  {15,204,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  55.  {22,209,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  56.  {16,108,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  57.  {20,206,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  58.  {17,223,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  59.  {19,222,TBSTATE_ENABLED,TBSTYLE_BUTTON,{0},0},
  60. };
  61. char *toolNames[]={
  62. "New game", "Open position", "Save position", "", 
  63. "Options", "Players settings", "Tournament", "Log window", "", 
  64. "Undo all","Undo 2x","Undo","Redo","Redo 2x",
  65. "Redo all","","Open skin","Next skin","Previous skin","Refresh",
  66. "Reset score","Continue","Pause","Swap players",
  67. "Connect","Disconnect",
  68. };
  69.  
  70.  
  71. char *priorTab[]={"idle","below normal","normal","above normal","high"};
  72.  
  73. Psquare
  74.  board=0,       
  75.  boardb, boardk,//pointer to the beginning and end of board
  76.  lastMove;      //pointer to last move
  77.  
  78. Tplayer players[2];     //information about players
  79. TturPlayer *turTable=0; //result of a tournament
  80. TturCell *turCells=0;
  81.          
  82. int
  83.  width=20,  //number of squares horizontally (without borders)
  84.  height=20, //number of squares vertically (without borders)
  85.  height2,   //height+2
  86.  player=1,  //who has turn
  87.  moves,     //moves counter
  88.  startMoves,//number of automatic opening moves
  89.  widthc,    //width of the client area of the window
  90.  widthb,    //right side of the board
  91.  heightb,   //bottom side of the board
  92.  coordW,    //width of coorninates at the left side
  93.  coordH,    //height of coorninates at the top side
  94.  mtop,      //toolBarH or 0
  95.  toolBarVisible=1,//1=show toolbar
  96.  maxMemory=80,   //maximum memory for AI (MB)
  97.  tolerance=1000, //how longer can AI think after timeout
  98.  hardTimeOut=0,  //should we check timeout for AI
  99.  humanTimeOut=0, //should we check timeout for human
  100.  exactFive=0,    //0= five or more stones win, 1=exactly 5 win
  101.  continuous=0,   //0= until someone wins, 1=until board is full
  102.  priority=2,     //AI process priority
  103.  autoBegin=0,    //automatic openings
  104.  opening,        //index of the current opening
  105.  turOpening,     //the current tournament opening
  106.  turRule=0,      //tournament mode
  107.  turRepeat=5,    //tournament repeat count
  108.  turCurRepeat,   //tournament repeat counter
  109.  turMatchRepeat=2,//number of games per one repeat cycle
  110.  turNplayers=0,  //number of tournament players
  111.  turRecord=0,    //save games
  112.  turOnlyLosses=0,//save only games which the first player lost
  113.  turFormat=1,    //1=psq,2=rec
  114.  turNet=0,       //0=local computer, 1=network
  115.  turTieRepeat=1, //maximal repeat count when it's a tie
  116.  turTieCounter,  //current number of sequential ties
  117.  whoConnect=0,   //0=tournament, 1=network game
  118.  logMessage=1,   //write message commands to the log window
  119.  logDebug=0,     //write debug commands to the log window
  120.  logMoves=1,     //write moves to the log window
  121.  infoEval=0,     //send INFO evaluate x,y when mouse moves
  122.  turLogMsg=1,    //write messages to messages.txt
  123.  suspendAI=1,    //1=suspend pbrains when it isn't their turn
  124.  debugAI=0,      //debug pbrains (when suspendAI==1)
  125.  statusY,        //status bar height
  126.  fontH,          //character height
  127.  invert=0,       //swap symbols
  128.  bmW,            //size of a square in pixels
  129.  sameTime=0,     //both players have the same timeGame and timeMove 
  130.  coordVisible=0, //show coordinates
  131.  mx,my,          //mouse coordinates
  132.  coordStart=0,   //coordinates origin, 0 or 1
  133.  moveStart=0,    //move number start, 0 or 1
  134.  moveDiv2=0,     //move number divide by two
  135.  flipHoriz,flipVert,flipDiag, //board inversion
  136.  hiliteDelay=600,//last move hilite duration 
  137.  clearLog=1,     //clear log window at the beginning of a game
  138.  turDelay=1500,  //pause between games in tournament
  139.  turGamesTotal,  //total number of games in tournament
  140.  turGamesCounter,//currently finished games in tournament
  141.  gotoMove,       //number in goto move dialog box
  142.  terminate,      //stopping AI
  143.  saveLock,
  144.  Naccel,
  145.  lastTime[2],    //displayed game times (used to avoid flicker)
  146.  lastTurnTime[2],//displayed turn times
  147.  ignoreErrors=1; //don't show error messages from AI
  148.  
  149. const int toolBarH=28; //toolbar height
  150.  
  151. DWORD lastTick;  //last move time (getTickCount())
  152.  
  153. char *title;     //window caption
  154. char turPlayerStr[50000]; //tournament players EXE file names
  155.  
  156. Psquare
  157.  hilited=0;      //hilited square
  158.  
  159. bool
  160.  isWin9X,      //1=Win95/98/ME, 0=WinNT/2K/XP
  161.  disableScore, //to avoid adding score more than once
  162.  levelChanged, //to not show timeout when time limit is decreased
  163.  turTimerAvail=false, //waiting between tournament games
  164.  cmdLineGame,  //command line argument -p
  165.  paused=true,  //game is paused
  166.  finished=true,//game has finished
  167.  delreg=false; //registry values were deleted
  168.  
  169. TfileName fnrec,fnskin,fnbrain,fnstate,TahDat,PlochaDat,TimeOutsDat,MsgDat,InfoDat;
  170. TdirName fntur,tempDir,dataDir;
  171. Txywh mainPos={50,15,0,0},logPos={500,40,0,0},msgPos={500,-1,0,0},resultPos;
  172.  
  173. HBITMAP bm;
  174. HDC dc,bmpdc;
  175. HWND hWin,logWnd,logDlg,resultDlg,msgWnd,msgDlg,toolbar;
  176. HINSTANCE inst;
  177. HACCEL haccel;
  178. ACCEL accel[Maccel];
  179. ACCEL dlgKey;
  180. HANDLE thread,pipeThread;
  181. HMODULE psapi;
  182. COLORREF colors[3];
  183. CRITICAL_SECTION timerLock;
  184. SIZE szScore,szCoord,szMove,szName[2],szTimeGame[2],szTimeMove[2];
  185.  
  186. TmemInfo getMemInfo;
  187.  
  188. OPENFILENAME psqOfn={
  189.  sizeof(OPENFILENAME),0, 0,0,0,0,1,
  190.  fnrec, sizeof(fnrec),
  191.  0,0,0, 0, 0,0,0, "PSQ", 0,0,0
  192. };
  193. OPENFILENAME skinOfn={
  194.  sizeof(OPENFILENAME),0, 0,0,0,0,1,
  195.  fnskin, sizeof(fnskin),
  196.  0,0,0, 0, 0,0,0, "BMP", 0,0,0
  197. };
  198. OPENFILENAME brainOfn={
  199.  sizeof(OPENFILENAME),0, 0,0,0,0,1,
  200.  fnbrain, sizeof(turPlayerStr),
  201.  0,0,0, 0, 0,0,0, "EXE", 0,0,0
  202. };
  203. OPENFILENAME stateOfn={
  204.  sizeof(OPENFILENAME),0, 0,0,0,0,1,
  205.  fnstate, sizeof(fnstate),
  206.  0,0,0, 0, 0,0,0, "TUR", 0,0,0
  207. };
  208.  
  209. const char
  210.  *subkey="Software\\Petr Lastovicka\\piskvorky";
  211. struct Treg { char *s; int *i; } regVal[]={
  212. {"height",&height},{"sirka",&width},
  213. {"hiliteDelay",&hiliteDelay},
  214. {"souradnice",&coordVisible},
  215. {"coordinatesOrigin",&coordStart},
  216. {"moveOrigin",&moveStart},
  217. {"X",&mainPos.x},{"Y",&mainPos.y},
  218. {"hraci0",&players[0].isComp},
  219. {"timeMove0",&players[0].timeMove},
  220. {"timeMove1",&players[1].timeMove},
  221. {"timeGame0",&players[0].timeGame},
  222. {"timeGame1",&players[1].timeGame},
  223. {"sameTime",&sameTime},
  224. {"prohodit",&invert},
  225. {"maxMemory",&maxMemory},
  226. {"tolerance",&tolerance},
  227. {"checkTimeOut",&hardTimeOut},
  228. {"moveDiv2",&moveDiv2},
  229. {"humanTimeOut",&humanTimeOut},
  230. {"tournamentRule",&turRule},
  231. {"tournamentRepeat",&turRepeat},
  232. {"tournamentDelay",&turDelay},
  233. {"tournamentRec",&turRecord},
  234. {"tournamentRecFormat",&turFormat},
  235. {"saveMsg",&turLogMsg},
  236. {"onlyLosses",&turOnlyLosses},
  237. {"flipHoriz",&flipHoriz},
  238. {"flipVert",&flipVert},
  239. {"flipDiag",&flipDiag},
  240. {"saveFormat",(int*)&psqOfn.nFilterIndex},
  241. {"logMessage",&logMessage},
  242. {"logDebug",&logDebug},
  243. {"logMoves",&logMoves},
  244. {"Xlog",&logPos.x},
  245. {"Ylog",&logPos.y},
  246. {"Wlog",&logPos.w},
  247. {"Hlog",&logPos.h},
  248. {"Xresult",&resultPos.x},
  249. {"Yresult",&resultPos.y},
  250. {"Wresult",&resultPos.w},
  251. {"Hresult",&resultPos.h},
  252. {"Xmsg",&msgPos.x},
  253. {"Ymsg",&msgPos.y},
  254. {"Wmsg",&msgPos.w},
  255. {"Hmsg",&msgPos.h},
  256. {"debugAI",&suspendAI},
  257. {"debugAI2",&debugAI},
  258. {"autoBegin",&autoBegin},
  259. {"opening",&opening},
  260. {"toolbar",&toolBarVisible},
  261. {"port",&port},
  262. {"net",&turNet},
  263. {"whoConnect",&whoConnect},
  264. {"priority",&priority},
  265. {"tieRepeat",&turTieRepeat},
  266. {"matchRepeat",&turMatchRepeat},
  267. {"infoEvaluate",&infoEval},
  268. {"logPipe",&debugPipe},
  269. {"exactFive",&exactFive},
  270. {"continuous",&continuous},
  271. {"clearLog",&clearLog},
  272. {"ignoreErrors",&ignoreErrors},
  273. };
  274. struct Tregs { char *s; char *i; DWORD n; } regValS[]={
  275. {"soubor",fnrec,sizeof(fnrec)},
  276. {"skin",fnskin,sizeof(fnskin)},
  277. {"language",lang,sizeof(lang)},
  278. {"AI0",players[0].brain,sizeof(players[0].brain)},
  279. {"AI1",players[1].brain,sizeof(players[1].brain)},
  280. {"tournamentPlayers",turPlayerStr,sizeof(turPlayerStr)},
  281. {"tournamentFolder",fntur,sizeof(fntur)},
  282. {"servername",servername,sizeof(servername)},
  283. {"AIfolder",AIfolder,sizeof(AIfolder)},
  284. {"cmdGame",cmdGameEnd,sizeof(cmdGameEnd)},
  285. {"cmdTur",cmdTurEnd,sizeof(cmdTurEnd)},
  286. {"AIdataFolder",dataDir,sizeof(dataDir)},
  287. };
  288. //------------------------------------------------------------------
  289. #define endA(a) (a+(sizeof(a)/sizeof(*a)))
  290.  
  291. void line(int x1,int y1,int x2,int y2)
  292. {
  293.   MoveToEx(dc, x1,y1, NULL);
  294.   LineTo(dc, x2,y2);
  295. }
  296.  
  297. void vprint(int x, int y, SIZE *sz, char *format, va_list va)
  298. {
  299.   char buf[128];
  300.   RECT rc;
  301.   int n;
  302.  
  303.   n = vsprintf(buf,format,va);
  304.   SetTextAlign(dc,TA_CENTER);
  305.   if(sz){
  306.     rc.left= x-(sz->cx>>1);
  307.     rc.right= x+(sz->cx>>1);
  308.     rc.top= y;
  309.     rc.bottom= y+sz->cy;
  310.     if(RectVisible(dc,&rc) || !sz->cx){
  311.       GetTextExtentPoint32(dc, buf, n, sz);
  312.     }
  313.   }
  314.   ExtTextOut(dc, x,y, sz ? ETO_OPAQUE:0, &rc, buf,n, 0);
  315. }
  316.  
  317. void print(int x, SIZE *sz, char *format, ...)
  318. {
  319.   va_list va;
  320.   va_start(va,format);
  321.   vprint(widthc*x/1000, heightb + (statusY/2-fontH)/2, sz, format,va);
  322.   va_end(va);
  323. }
  324.  
  325. void print2(int x, SIZE *sz, char *format, ...)
  326. {
  327.   va_list va;
  328.   va_start(va,format);
  329.   vprint(widthc*x/1000, heightb + (statusY*3/2-fontH)/2, sz, format,va);
  330.   va_end(va);
  331. }
  332.  
  333. void printMoves()
  334. {
  335.   print2(500,&szMove, lng(550,"Move %d"), moveStart + (moveDiv2 ? (moves-finished)/2 : moves));
  336. }
  337.  
  338. void printScore()
  339. {
  340.   print(500,&szScore, lng(553,"Score %d:%d"),
  341.     players[0].score, players[1].score);
  342. }
  343.  
  344. void printMouseCoord()
  345. {
  346.   if(mx>=0 && my>=0 && mx<width && my<height && coordVisible){
  347.     print2(650,&szCoord," [%2d,%2d] " , mx+coordStart, my+coordStart);
  348.   }else{
  349.     print2(650,&szCoord,"");
  350.   }
  351. }
  352.  
  353. static int brainX[2]={220,771};
  354.  
  355. void printLevel1()
  356. {
  357.   for(int i=0; i<2; i++){
  358.     char buf[17];
  359.     players[i].getName(buf,sizeof(buf));
  360.     print(brainX[i], &szName[i], buf);
  361.   }
  362. }
  363.  
  364. void checkMenus()
  365. {
  366.   HMENU h=GetMenu(hWin);
  367.   CheckMenuRadioItem(h,401,403,401 + players[0].isComp + players[1].isComp,MF_BYCOMMAND);
  368.   CheckMenuItem(h,309,toolBarVisible ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
  369. }
  370.  
  371. void printLevel()
  372. {
  373.   printLevel1();
  374.   checkMenus();
  375. }
  376.  
  377. int whoStarted()
  378. {
  379.   return player^(moves&1);
  380. }
  381.  
  382. int vmsg(char *caption, char *text, int btn, va_list v)
  383. {
  384.   char buf[1024];
  385.   if(!text) return IDCANCEL;
  386.   _vsnprintf(buf,sizeof(buf),text,v);
  387.   buf[sizeof(buf)-1]=0;
  388.   return MessageBox(hWin,buf,caption,btn);
  389. }
  390.  
  391. void msglng(int id, char *text, ...)
  392. {
  393.   va_list ap;
  394.   va_start(ap,text);
  395.   vmsg(title,lng(id,text),MB_OK|MB_ICONERROR,ap);
  396.   va_end(ap);
  397. }
  398.  
  399. int msg3(int btn, char *caption, char *text, ...)
  400. {
  401.   va_list ap;
  402.   va_start(ap,text);
  403.   int result = vmsg(caption,text,btn,ap);
  404.   va_end(ap);
  405.   return result;
  406. }
  407.  
  408. void msg2(char *caption, char *text, ...)
  409. {
  410.   va_list ap;
  411.   va_start(ap,text);
  412.   vmsg(caption,text,MB_OK|MB_ICONERROR,ap);
  413.   va_end(ap);
  414. }
  415.  
  416. int msg1(int btn, char *text, ...)
  417. {
  418.   va_list ap;
  419.   va_start(ap,text);
  420.   int result = vmsg(title,text,btn,ap);
  421.   va_end(ap);
  422.   return result;
  423. }
  424.  
  425. void msg(char *text, ...)
  426. {
  427.   va_list ap;
  428.   va_start(ap,text);
  429.   vmsg(title,text,MB_OK|MB_ICONERROR,ap);
  430.   va_end(ap);
  431. }
  432.  
  433. void vwrLog(char *text, va_list ap)
  434. {
  435.   char *buf;
  436.   int len,n;
  437.  
  438.   buf=0;
  439.   if(text){
  440.     for(len=64; ;len*=2){
  441.       delete[] buf;
  442.       buf=new char[len+3];
  443.       n=_vsnprintf(buf,len,text,ap);
  444.       if(n>=0) break;
  445.     }
  446.     buf[n]='\r';
  447.     buf[n+1]='\n';
  448.     buf[n+2]=0;
  449.   }
  450.   PostMessage(hWin,WM_COMMAND,998,(LPARAM)buf);
  451. }
  452.  
  453. void wrLog(char *text, ...)
  454. {
  455.   va_list ap;
  456.   va_start(ap,text);
  457.   vwrLog(text,ap);
  458.   va_end(ap);
  459. }
  460.  
  461. int getRadioButton(HWND hWnd, int item1, int item2)
  462. {
  463.   for(int i=item1; i<=item2; i++){
  464.     if(IsDlgButtonChecked(hWnd,i)){
  465.       return i-item1;
  466.     }
  467.   }
  468.   return 0;
  469. }
  470.  
  471. void browseFolder(char *buf, HWND wnd,int item, char *txt)
  472. {
  473.   BROWSEINFO bi;
  474.   bi.hwndOwner= wnd;
  475.   bi.pidlRoot=0;
  476.   bi.pszDisplayName= buf;
  477.   bi.lpszTitle= txt;
  478.   bi.ulFlags=BIF_RETURNONLYFSDIRS;
  479.   bi.lpfn=0;
  480.   bi.iImage=0;
  481.   ITEMIDLIST *iil;
  482.   iil=SHBrowseForFolder(&bi);
  483.   if(iil){
  484.     if(SHGetPathFromIDList(iil,buf)){
  485.       SetDlgItemText(wnd,item,buf);
  486.     }
  487.     IMalloc *ma;
  488.     SHGetMalloc(&ma);
  489.     ma->Free(iil);
  490.     ma->Release();
  491.   }
  492. }
  493.  
  494. void delDir(char *path,bool d)
  495. {
  496.   HANDLE h;
  497.   WIN32_FIND_DATA fd;
  498.   char oldDir[256];
  499.   
  500.   GetCurrentDirectory(sizeof(oldDir), oldDir);
  501.   if(!SetCurrentDirectory(path)) return;
  502.   h = FindFirstFile("*", &fd);
  503.   if(h!=INVALID_HANDLE_VALUE){
  504.     do{
  505.       if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  506.         if(fd.cFileName[0]!='.' || (fd.cFileName[1] && fd.cFileName[1]!='.')){
  507.           delDir(fd.cFileName,true);
  508.         }
  509.         continue;
  510.       }
  511.       DeleteFile(fd.cFileName);
  512.     }while(FindNextFile(h,&fd));
  513.     FindClose(h);
  514.   }
  515.   SetCurrentDirectory(oldDir);
  516.   if(d) RemoveDirectory(path);
  517. }
  518.  
  519. void cleanTemp()
  520. {
  521.  HANDLE h,p;
  522.  DWORD i;
  523.  TfileName buf;
  524.  WIN32_FIND_DATA fd;
  525.  
  526.  //delete all temporary folders
  527.  GetTempPath(sizeof(buf)-8,buf);
  528.  if(!SetCurrentDirectory(buf)) return;
  529.  h = FindFirstFile("psqp*", &fd);
  530.  if(h!=INVALID_HANDLE_VALUE){
  531.    do{
  532.      if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  533.        if(sscanf(fd.cFileName+4,"%d",&i)==1){
  534.          p=OpenProcess(STANDARD_RIGHTS_REQUIRED,FALSE,i);
  535.          if(p){
  536.            CloseHandle(p);
  537.          }else{
  538.            delDir(fd.cFileName,true);
  539.          }
  540.        }
  541.      }
  542.    }while(FindNextFile(h,&fd));
  543.    FindClose(h);
  544.  }
  545. }
  546.  
  547. int checkDir(HWND hDlg, int item)
  548. {
  549.   TdirName dir,buf;
  550.   char *p;
  551.  
  552.   GetDlgItemText(hDlg,item,buf,sizeof(buf));
  553.   if(!buf[0]) GetCurrentDirectory(sizeof(dir),dir);
  554.   else GetFullPathName(buf,sizeof(dir),dir,&p);
  555.   SetDlgItemText(hDlg,item,dir);
  556.   DWORD attr= GetFileAttributes(dir);
  557.   if(attr!=0xFFFFFFFF && (attr&FILE_ATTRIBUTE_DIRECTORY)) return 2;
  558.   if(CreateDirectory(dir,0)) return 1;
  559.   msglng(816,"Cannot create folder %s",dir);
  560.   SetFocus(GetDlgItem(hDlg,item));
  561.   return 0;
  562. }
  563.  
  564. int close(FILE *f,char *fn)
  565. {
  566.   if(!fclose(f)) return 0;
  567.   if( msg1(MB_ICONEXCLAMATION|MB_RETRYCANCEL,
  568.     lng(734,"Write error, file %s"), fn)
  569.     ==IDRETRY) return 2;
  570.   return 1;
  571. }
  572.  
  573. int getDlgItemMs(HWND hDlg,int item)
  574. {
  575.   char buf[32],*s;
  576.   GetDlgItemText(hDlg,item,buf,sizeof(buf));
  577.   for(s=buf; *s; s++){
  578.     if(*s==',') *s='.';
  579.   }
  580.   return int(strtod(buf,0)*1000);
  581. }
  582.  
  583. void setDlgItemMs(HWND hDlg,int item,int ms)
  584. {
  585.   char buf[32];
  586.   sprintf(buf,"%g",double(ms)/1000.0);
  587.   SetDlgItemText(hDlg,item,buf);
  588. }
  589.  
  590. enum { R_left=1, R_right=2, R_top=4, R_bottom=8 };
  591.  
  592. struct Tresize {
  593.   int id;
  594.   int flags;
  595. };
  596.  
  597. void resize(Txywh &pos, const Tresize *data, int len, HWND hWnd, UINT mesg, LPARAM lP)
  598. {
  599.   int i,dw,dh;
  600.   RECT rc;
  601.  
  602.   switch(mesg){
  603.   case WM_INITDIALOG:
  604.     SendMessage(hWnd,WM_SETICON,ICON_SMALL,(LPARAM)LoadIcon(inst,MAKEINTRESOURCE(1)));
  605.     GetClientRect(hWnd,&rc);
  606.     pos.oldW= rc.right-rc.left;
  607.     pos.oldH= rc.bottom-rc.top;
  608.     aminmax(pos.x,-20,GetSystemMetrics(SM_CXSCREEN)-100);
  609.     aminmax(pos.y,-5,GetSystemMetrics(SM_CYSCREEN)-80);
  610.     break;
  611.   case WM_MOVE:
  612.   case WM_EXITSIZEMOVE:
  613.     if(!IsZoomed(hWnd) && !IsIconic(hWnd)){
  614.       GetWindowRect(hWnd,&rc);
  615.       pos.x= rc.left;
  616.       pos.y= rc.top;
  617.       pos.w= rc.right-rc.left;
  618.       pos.h= rc.bottom-rc.top;
  619.     }
  620.     break;
  621.   case WM_SIZE:
  622.     if(!lP) break;
  623.     if(pos.oldW){
  624.       HDWP p=BeginDeferWindowPos(len);
  625.       for(i=0; i<len; i++){
  626.         const Tresize *d= data+i;
  627.         HWND w= GetDlgItem(hWnd,d->id);
  628.         GetWindowRect(w,&rc);
  629.         MapWindowPoints(0,hWnd,(POINT*)&rc,2);
  630.         dw=LOWORD(lP)-pos.oldW;
  631.         dh=HIWORD(lP)-pos.oldH;
  632.         if(d->flags&R_left) rc.left+=dw;
  633.         if(d->flags&R_right) rc.right+=dw;
  634.         if(d->flags&R_top) rc.top+=dh;
  635.         if(d->flags&R_bottom) rc.bottom+=dh;
  636.         DeferWindowPos(p,w,0,rc.left,rc.top,
  637.           rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER);
  638.       }
  639.       EndDeferWindowPos(p);
  640.     }
  641.     pos.oldW=LOWORD(lP);
  642.     pos.oldH=HIWORD(lP);                
  643.     break;
  644.     case WM_GETMINMAXINFO:
  645.      ((MINMAXINFO FAR*) lP)->ptMinTrackSize.x = 170;
  646.      ((MINMAXINFO FAR*) lP)->ptMinTrackSize.y = 150;
  647.     break;
  648.   }
  649. }
  650. //-----------------------------------------------------------------
  651.  
  652. Psquare Square(int x,int y)
  653. {
  654.   return boardb + x*height2+(y+1);
  655. }
  656.  
  657. int X(Psquare p)
  658. {
  659.   int x;
  660.  
  661.   if(flipDiag){
  662.     x=p->y;
  663.     if(flipHoriz) x=height+1-x;
  664.   }else{
  665.     x=p->x;
  666.     if(flipHoriz) x=width+1-x;
  667.   }
  668.   x= (x-1)*bmW;
  669.   if(coordVisible) x+=coordW;
  670.   return x;
  671. }
  672.  
  673. int Y(Psquare p)
  674. {
  675.   int y;
  676.  
  677.   if(flipDiag){
  678.     y=p->x;
  679.     if(flipVert) y=width+1-y;
  680.   }else{
  681.     y=p->y;
  682.     if(flipVert) y=height+1-y;
  683.   }
  684.   y= (y-1)*bmW;
  685.   if(coordVisible) y+=coordH;
  686.   if(toolBarVisible) y+=toolBarH;
  687.   return y;
  688. }
  689.  
  690. void getMousePos(WPARAM lP, int &x0, int &y0)
  691. {
  692.   int w,x,y;
  693.   x=LOWORD(lP);
  694.   y=HIWORD(lP);
  695.   if(coordVisible) x-=coordW, y-=coordH;
  696.   if(toolBarVisible) y-=toolBarH;
  697.   x=x/bmW; y=y/bmW;
  698.   if(flipHoriz) x=(flipDiag?height:width)-1-x;
  699.   if(flipVert) y=(flipDiag?width:height)-1-y;
  700.   if(flipDiag) w=x,x=y,y=w;
  701.   x0=x; y0=y;
  702. }
  703.  
  704. bool onAIName(int i, LPARAM lP)
  705. {
  706.   return HIWORD(lP)>heightb && 
  707.     abs(LOWORD(lP)-widthc*brainX[i]/1000)<30;
  708. }
  709.  
  710. //draw square at position p
  711. //z: 0=empty, 1=first player, 2=second player, 3=outside
  712. void paintSquare(int z, Psquare p)
  713. {
  714.   if(z>2) return;
  715.   if(z){
  716.     if(invert) z^=3;
  717.     if(p==hilited) z+=2;
  718.   }
  719.   BitBlt(dc,X(p),Y(p), bmW, bmW, bmpdc, z*bmW,0,SRCCOPY);
  720. }
  721.  
  722. void paintSquare(Psquare p)
  723. {
  724.   paintSquare(p->z, p);
  725. }
  726. //-----------------------------------------------------------------
  727. void cancelHilite()
  728. {
  729.   Psquare p=hilited;
  730.   if(p){
  731.     hilited=0;
  732.     paintSquare(p);
  733.     KillTimer(hWin,10);
  734.   }
  735. }
  736.  
  737. //hilite last move
  738. void hiliteLast()
  739. {
  740.   cancelHilite();
  741.   if(moves && hiliteDelay && !lastMove->winLineDir){
  742.     SetTimer(hWin,10, hiliteDelay, NULL);
  743.     paintSquare(hilited=lastMove);
  744.   }
  745. }
  746.  
  747. void showLast()
  748. {
  749.   int d=hiliteDelay;
  750.   if(d<100) hiliteDelay=700;
  751.   hiliteLast();
  752.   hiliteDelay=d;
  753. }
  754. //-----------------------------------------------------------------
  755. DWORD getTickCount()
  756. {
  757.   static LARGE_INTEGER freq;
  758.   if(!freq.QuadPart){
  759.     QueryPerformanceFrequency(&freq);
  760.     if(!freq.QuadPart) return GetTickCount();
  761.   }
  762.   LARGE_INTEGER c;
  763.   QueryPerformanceCounter(&c);
  764.   return (DWORD)(c.QuadPart*1000/freq.QuadPart);
  765. }
  766.  
  767. void printTime(int pl)
  768. {
  769.   int t,c,y,x0,x;
  770.   HGDIOBJ oldP;
  771.   HPEN pen0,pen1;
  772.   int W;
  773.   static const int X1[2]={60,940}, X2[2]={45,955};
  774.  
  775.   //prepare pens
  776.   pen0= CreatePen(PS_SOLID,0,colors[0]);
  777.   pen1= CreatePen(PS_SOLID,0,colors[1]);
  778.   oldP= GetCurrentObject(dc,OBJ_PEN);
  779.   W=widthc/9;
  780.   x0=0; 
  781.   if(pl) x0=widthc-W;
  782.   t=players[pl].time;
  783.   //turn time
  784.   if(pl==player && !paused && (moves>0 || players[pl].isComp)){
  785.     c=getTickCount()-lastTick;
  786.     t+=c;
  787.     lastTurnTime[pl]=c;
  788.     players[pl].checkTimeOut(c);
  789.   }
  790.   print2(X1[pl], &szTimeMove[pl], "%.1f", 
  791.     double(lastTurnTime[pl])/1000.0);
  792.   if(players[pl].timeMove>400 && !isNetGame){
  793.     //progress
  794.     y= heightb+(statusY*3/2+fontH)/2+1;
  795.     x= W-W*lastTurnTime[pl]/players[pl].timeMove;
  796.     if(x>0){
  797.       amax(x,W);
  798.       SelectObject(dc,pen1);
  799.       line(x0,y,x0+x,y);
  800.     }else{
  801.       x=0;
  802.     }
  803.     SelectObject(dc,pen0);
  804.     line(x0+x,y,x0+W,y);
  805.   }
  806.   //game time
  807.   t/=1000;
  808.   if(t!=lastTime[pl]){
  809.     lastTime[pl]=t;
  810.     print(X2[pl], &szTimeGame[pl], "%d:%02d", t/60, t%60);
  811.     if(players[pl].timeGame && !isNetGame){
  812.       //progress
  813.       y= heightb+(statusY/2+fontH)/2+1;
  814.       x= W-W*t/players[pl].timeGame;
  815.       if(x>0){
  816.         amax(x,W);
  817.         SelectObject(dc,pen1);
  818.         line(x0,y,x0+x,y);
  819.       }else{
  820.         x=0;
  821.       }
  822.       SelectObject(dc,pen0);
  823.       line(x0+x,y,x0+W,y);
  824.     }
  825.   }
  826.   //delete pens
  827.   SelectObject(dc,oldP);
  828.   DeleteObject(pen1);
  829.   DeleteObject(pen0);
  830. }
  831.  
  832. bool getWinLine(Psquare p, Psquare &p2)
  833. {
  834.   int s;
  835.   Psquare p1;
  836.  
  837.   s=p->winLineDir;
  838.   if(!s) return false;
  839.   p1=p->winLineStart;
  840.   do{
  841.     nxtP(p,1);
  842.   }while(p->winLineStart==p1);
  843.   prvP(p,1);
  844.   p2=p;
  845.   return true;
  846. }
  847.  
  848. void printWinLine(Psquare p)
  849. {
  850.   Psquare p2;
  851.   RECT rc;
  852.   LONG w;
  853.  
  854.   if(!getWinLine(p,p2)) return;
  855.   rc.left=X(p->winLineStart);
  856.   rc.top=Y(p->winLineStart);
  857.   rc.right=X(p2);
  858.   rc.bottom=Y(p2);
  859.   if(rc.left>rc.right) w=rc.left,rc.left=rc.right,rc.right=w;
  860.   if(rc.top>rc.bottom) w=rc.top,rc.top=rc.bottom,rc.bottom=w;
  861.   rc.right+=bmW;
  862.   rc.bottom+=bmW;
  863.   InvalidateRect(hWin,&rc,FALSE);
  864. }
  865.  
  866. void status()
  867. {
  868.   printMoves();
  869.   printScore();
  870.   printLevel();
  871.   printTime(0);
  872.   printTime(1);
  873.   printMouseCoord();
  874.   BitBlt(dc, widthc*brainX[0]/1000-bmW/2, heightb+statusY/2, bmW-1, bmW-1,
  875.     bmpdc, (invert+1)*bmW+1, 1,SRCCOPY);
  876.   BitBlt(dc, widthc*brainX[1]/1000-bmW/2, heightb+statusY/2, bmW-1, bmW-1,
  877.     bmpdc, (2-invert)*bmW+1, 1,SRCCOPY);
  878.   if(!turNplayers) print2(brainX[whoStarted()]+45,0,"*");
  879. }
  880.  
  881. //paint entire window
  882. void repaint(RECT *clip)
  883. {
  884.   HGDIOBJ penOld;
  885.   HBRUSH brush;
  886.   Psquare p,p2;
  887.   RECT rc;
  888.   int i,d,j;
  889.   char buf[4];
  890.   
  891.   brush= CreateSolidBrush(colors[0]);
  892.   if(coordVisible){
  893.     //left
  894.     rc.left=0;
  895.     rc.right=coordW;
  896.     rc.top=mtop;
  897.     rc.bottom= heightb;
  898.     FillRect(dc,&rc,brush);
  899.     //top
  900.     rc.left= coordW;
  901.     rc.right=widthb;
  902.     rc.bottom= rc.top+coordH;
  903.     FillRect(dc,&rc,brush);
  904.   }
  905.   //right border
  906.   rc.left= widthb;
  907.   rc.right=widthc;
  908.   if(rc.left<rc.right){
  909.     rc.top=mtop;
  910.     rc.bottom= heightb;
  911.     FillRect(dc,&rc,brush);
  912.   }
  913.   //status bar
  914.   if(clip->bottom>heightb){
  915.     rc.top=heightb;
  916.     rc.bottom=rc.top+statusY;
  917.     rc.left=0;
  918.     FillRect(dc,&rc,brush);
  919.     lastTime[0]=lastTime[1]=-1;
  920.     status();
  921.   }
  922.   DeleteObject(brush);
  923.   //coordinates
  924.   if(coordVisible){
  925.     //top
  926.     if(clip->top < mtop+coordH){
  927.       SetTextAlign(dc,TA_CENTER|TA_TOP);
  928.       d= (flipDiag ? height:width)-1;
  929.       for(i=d; i>=0; i--){
  930.         j=i;
  931.         if(flipHoriz) j=d-j;
  932.         itoa(j+coordStart,buf,10);
  933.         TextOut(dc,i*bmW+(bmW/2)+coordW,mtop,buf,(int)strlen(buf));
  934.       }
  935.     }
  936.     //left
  937.     if(clip->left < coordW){
  938.       SetTextAlign(dc,TA_RIGHT|TA_BASELINE);
  939.       d= (flipDiag ? width:height)-1;
  940.       for(i=d; i>=0; i--){
  941.         j=i;
  942.         if(flipVert) j=d-j;
  943.         itoa(j+coordStart,buf,10);
  944.         TextOut(dc,coordW-4,(i+1)*bmW-5+coordH+mtop,buf,(int)strlen(buf));
  945.       }
  946.     }
  947.   }
  948.   //board
  949.   for(p=boardb; p<boardk; p++)  paintSquare(p);
  950.   //border
  951.   d=0;
  952.   if(coordVisible) d=coordH;
  953.   if(toolBarVisible) d+=toolBarH;
  954.   for(i=(flipDiag?width:height)-1; i>=0; i--){
  955.     BitBlt(dc, widthb-1, i*bmW+d, 1, bmW, bmpdc, 0,0,SRCCOPY);
  956.   }
  957.   d= coordVisible ? coordW : 0;
  958.   for(i=(flipDiag?height:width)-1; i>=0; i--){
  959.     BitBlt(dc, i*bmW+d, heightb-1, bmW,1, bmpdc, 0,0,SRCCOPY);
  960.   }
  961.   SetPixel(dc, widthb-1, heightb-1, GetPixel(bmpdc, 0,0));
  962.   //winning lines through five or more squares
  963.   for(p=boardb; p<boardk; p++){
  964.     if(p==p->winLineStart){
  965.       getWinLine(p,p2);
  966.       penOld= SelectObject(dc,CreatePen(PS_SOLID,3,colors[2]));
  967.       line(X(p) + bmW/2, Y(p) + bmW/2, X(p2) + bmW/2, Y(p2) + bmW/2);
  968.       DeleteObject(SelectObject(dc,penOld));
  969.     }
  970.   }
  971. }
  972.  
  973. void invalidate()
  974. {
  975.   int i,w,h;
  976.   SIZE sz;
  977.   RECT rc,rcw;
  978.  
  979.   fontH= HIWORD(GetDialogBaseUnits());
  980.   statusY= max(bmW*2,fontH*2+4);
  981.   heightb = height*bmW+1;
  982.   widthb = width*bmW+1;
  983.   coordH=fontH;
  984.   coordW=fontH+8;
  985.   if(flipDiag){
  986.     w=heightb; heightb=widthb; widthb=w;
  987.   }
  988.   if(coordVisible) heightb+=coordH, widthb+=coordW;
  989.   heightb+=mtop;
  990.   widthc = max(widthb,400);
  991.   if(SendMessage(toolbar,TB_GETMAXSIZE,0,(LPARAM)&sz)){
  992.     amin(widthc,sz.cx);
  993.   }
  994.   if(!IsIconic(hWin)){
  995.     for(i=0; i<2; i++){
  996.       GetClientRect(hWin,&rc);
  997.       GetWindowRect(hWin,&rcw);
  998.       w= widthc + rcw.right-rcw.left-rc.right;
  999.       h= heightb + statusY + rcw.bottom-rcw.top-rc.bottom;
  1000.       if(w!= rcw.right-rcw.left || h!= rcw.bottom-rcw.top){
  1001.         SetWindowPos(hWin,0,0,0, w,h, SWP_NOMOVE|SWP_NOZORDER);
  1002.         SendMessage(toolbar, TB_AUTOSIZE, 0,0);
  1003.       }
  1004.     }
  1005.     GetClientRect(hWin,&rc);
  1006.     rc.top=mtop;
  1007.     InvalidateRect(hWin,&rc,FALSE);
  1008.   }
  1009. }
  1010.  
  1011. //-----------------------------------------------------------------
  1012. void copyToClipboard(HWND wnd)
  1013. {
  1014.   HGLOBAL hmem;
  1015.   char *ptr;
  1016.   int i= GetWindowTextLength(wnd)+1;
  1017.   if(OpenClipboard(0)){
  1018.     if(EmptyClipboard()){
  1019.       if((hmem=GlobalAlloc(GMEM_DDESHARE, isWin9X ? i : 2*i))!=0){
  1020.         if((ptr=(char*)GlobalLock(hmem))!=0){
  1021.           if(isWin9X) GetWindowText(wnd,ptr,i);
  1022.           else ((int(WINAPI*)(HWND,char*,int))GetProcAddress(GetModuleHandle("user32.dll"),"GetWindowTextW"))(wnd,ptr,i);
  1023.           GlobalUnlock(hmem);
  1024.           SetClipboardData(isWin9X ? CF_TEXT : CF_UNICODETEXT, hmem);
  1025.         }else{
  1026.           GlobalFree(hmem);
  1027.         }
  1028.       }
  1029.     }
  1030.     CloseClipboard();
  1031.   }
  1032. }
  1033.  
  1034. void openPsq()
  1035. {
  1036.   for(;;){
  1037.     psqOfn.hwndOwner= hWin;
  1038.     psqOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY|OFN_NOCHANGEDIR;
  1039.     if(GetOpenFileName(&psqOfn)){
  1040.       openPsq(psqOfn.lpstrFile);
  1041.       break; //ok
  1042.     }
  1043.     if(CommDlgExtendedError()!=FNERR_INVALIDFILENAME
  1044.       || !psqOfn.lpstrFile[0]) break; //cancel
  1045.     psqOfn.lpstrFile[0]=0;
  1046.   }
  1047. }
  1048.  
  1049. void savePsq()
  1050. {
  1051.   if(!lastMove) return;
  1052.   saveLock++;
  1053.   for(;;){
  1054.     psqOfn.hwndOwner= hWin;
  1055.     psqOfn.Flags= OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
  1056.     if(GetSaveFileName(&psqOfn)){
  1057.       savePsq(psqOfn.lpstrFile, psqOfn.nFilterIndex);
  1058.       break; //ok
  1059.     }
  1060.     if(CommDlgExtendedError()!=FNERR_INVALIDFILENAME
  1061.       || !psqOfn.lpstrFile[0]) break; //cancel
  1062.     psqOfn.lpstrFile[0]=0;
  1063.   }
  1064.   saveLock--;
  1065. }
  1066.  
  1067. //-----------------------------------------------------------------
  1068. char *loadSkin(HBITMAP fbmp)
  1069. {
  1070.   int w,h;
  1071.   BITMAP bmp;
  1072.   char *errs;
  1073.   
  1074.   if(!fbmp){
  1075.     errs= lng(700,"Cannot create bitmap for skin");
  1076.   }else{
  1077.     GetObject(fbmp,sizeof(BITMAP),&bmp);
  1078.     w= bmp.bmWidth;
  1079.     h= bmp.bmHeight;
  1080.     if(w != 5*h + 1){
  1081.       errs=lng(701,"Bitmap has wrong size");
  1082.     }else{
  1083.       bmW=h;
  1084.       DeleteObject(SelectObject(bmpdc,fbmp));
  1085.       bm=fbmp;
  1086.       for(int i=0; i<3; i++){
  1087.         colors[i]= GetPixel(bmpdc,bmW*5,i);
  1088.       }
  1089.       SetBkColor(dc,colors[0]);
  1090.       SetTextColor(dc,colors[1]);
  1091.       errs=0;
  1092.     }
  1093.   }
  1094.   return errs;
  1095. }
  1096. //-----------------------------------------------------------------
  1097. char* loadSkin()
  1098. {
  1099.   BITMAPFILEHEADER hdr;
  1100.   HANDLE h;
  1101.   DWORD r,s;
  1102.   char *errs= lng(702,"Can't read BMP file");
  1103.   
  1104.   h= CreateFile(fnskin, GENERIC_READ,FILE_SHARE_READ,
  1105.     0,OPEN_EXISTING,0,0);
  1106.   if(h!=INVALID_HANDLE_VALUE){
  1107.     ReadFile(h,&hdr,sizeof(BITMAPFILEHEADER),&r,0);
  1108.     if(r==sizeof(BITMAPFILEHEADER) && ((char*)&hdr.bfType)[0]=='B' && ((char*)&hdr.bfType)[1]=='M'){
  1109.       s = GetFileSize(h,0) - sizeof(BITMAPFILEHEADER);
  1110.       char *b= new char[s];
  1111.       if(b){
  1112.         ReadFile(h,b,s,&r,0);
  1113.         if(r==s){
  1114.           HBITMAP bm1 = CreateDIBitmap(dc, (BITMAPINFOHEADER*)b,
  1115.             CBM_INIT, b+hdr.bfOffBits-sizeof(BITMAPFILEHEADER),
  1116.             (BITMAPINFO*)b, DIB_RGB_COLORS);
  1117.           errs= loadSkin(bm1);
  1118.           invalidate();
  1119.         }
  1120.       }
  1121.       delete[] b;
  1122.     }
  1123.     CloseHandle(h);
  1124.   }
  1125.   return errs;
  1126. }
  1127. //-----------------------------------------------------------------
  1128. void openSkin()
  1129. {
  1130.   skinOfn.hwndOwner= hWin;
  1131.   skinOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY|OFN_NOCHANGEDIR;
  1132.   if(GetOpenFileName(&skinOfn)){
  1133.     char *err= loadSkin();
  1134.     msg(err);
  1135.   }else{
  1136.     if(CommDlgExtendedError()==FNERR_INVALIDFILENAME && *fnskin){
  1137.       *fnskin=0;
  1138.       openSkin();
  1139.     }
  1140.   }
  1141. }
  1142. //-----------------------------------------------------------------
  1143. char *onlyExt(char *dest)
  1144. {
  1145.   char *s;
  1146.   
  1147.   if(!*fnskin) strcpy(fnskin,"skins\\*.bmp");
  1148.   strcpy(dest, fnskin);
  1149.   for(s=strchr(dest,0); s>=dest && *s!='\\'; s--) ;
  1150.   s++;
  1151.   strcpy(s,"*.bmp");
  1152.   return fnskin + (s-dest);
  1153. }
  1154. //-----------------------------------------------------------------
  1155. void prevSkin()
  1156. {
  1157.   WIN32_FIND_DATA fd;
  1158.   TfileName buf,prev;
  1159.   HANDLE h;
  1160.   char *t;
  1161.   int pass=0;
  1162.   
  1163.   t= onlyExt(buf);
  1164.   h= FindFirstFile(buf,&fd);
  1165.   if(h==INVALID_HANDLE_VALUE){
  1166.     openSkin();
  1167.   }else{
  1168.     *prev=0;
  1169.     do{
  1170.       if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  1171.         if(!stricmp(t,fd.cFileName) || pass>10){
  1172.           strcpy(t, prev);
  1173.           if(!loadSkin()) break;
  1174.         }else{
  1175.           strcpy(prev, fd.cFileName);
  1176.         }
  1177.       }
  1178.       if(!FindNextFile(h,&fd)){
  1179.         FindClose(h);
  1180.         h = FindFirstFile(buf,&fd);
  1181.         pass++;
  1182.       }
  1183.     }while(pass<20);
  1184.     FindClose(h);
  1185.   }
  1186. }
  1187. //-----------------------------------------------------------------
  1188. void nextSkin()
  1189. {
  1190.   WIN32_FIND_DATA fd;
  1191.   TfileName buf;
  1192.   HANDLE h;
  1193.   char *t;
  1194.   int pass=0;
  1195.   
  1196.   t= onlyExt(buf);
  1197.   h= FindFirstFile(buf,&fd);
  1198.   if(h==INVALID_HANDLE_VALUE){
  1199.     openSkin();
  1200.   }else{
  1201.     do{
  1202.       if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  1203.         if(pass){
  1204.           strcpy(t, fd.cFileName);
  1205.           if(!loadSkin()) break;
  1206.         }
  1207.         else if(!stricmp(t,fd.cFileName)) pass++;
  1208.       }
  1209.       if(!FindNextFile(h,&fd)){
  1210.         FindClose(h);
  1211.         h = FindFirstFile(buf,&fd);
  1212.         pass++;
  1213.       }
  1214.     }while(pass<3);
  1215.     FindClose(h);
  1216.   }
  1217. }
  1218. //-----------------------------------------------------------------
  1219. void deleteini()
  1220. {
  1221.   HKEY key;
  1222.   DWORD i;
  1223.   
  1224.   delreg=true;
  1225.   if(RegDeleteKey(HKEY_CURRENT_USER, subkey)==ERROR_SUCCESS){
  1226.     if(RegOpenKey(HKEY_CURRENT_USER,
  1227.       "Software\\Petr Lastovicka",&key)==ERROR_SUCCESS){
  1228.       i=1;
  1229.       RegQueryInfoKey(key,0,0,0,&i,0,0,0,0,0,0,0);
  1230.       RegCloseKey(key);
  1231.       if(!i)
  1232.         RegDeleteKey(HKEY_CURRENT_USER, "Software\\Petr Lastovicka");
  1233.     }
  1234.   }
  1235. }
  1236.  
  1237. void writeini()
  1238. {
  1239.   HKEY key;
  1240.   if(RegCreateKey(HKEY_CURRENT_USER, subkey, &key)!=ERROR_SUCCESS)
  1241.     msglng(735,"Cannot write to Windows registry");
  1242.   else{
  1243.     for(Treg *u=regVal; u<endA(regVal); u++){
  1244.       RegSetValueEx(key, u->s, 0,REG_DWORD,
  1245.         (BYTE *)u->i, sizeof(int));
  1246.     }
  1247.     for(Tregs *v=regValS; v<endA(regValS); v++){
  1248.       RegSetValueEx(key, v->s, 0,REG_SZ,
  1249.         (BYTE *)v->i, strlen(v->i)+1);
  1250.     }
  1251.     RegSetValueExA(key, "keys", 0,REG_BINARY, (BYTE *)accel, Naccel*sizeof(ACCEL));
  1252.     TBSAVEPARAMS sp;
  1253.     sp.hkr=key;
  1254.     sp.pszSubKey="";
  1255.     sp.pszValueName="toolbar";
  1256.     SendMessage(toolbar,TB_SAVERESTORE,TRUE,(LPARAM)&sp);
  1257.     RegCloseKey(key);
  1258.   }
  1259. }
  1260.  
  1261. void readini()
  1262. {
  1263.   HKEY key;
  1264.   DWORD d;
  1265.  
  1266.   if(RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &key)==ERROR_SUCCESS){
  1267.     d=sizeof(dataDir);
  1268.     RegQueryValueEx(key,"Common AppData",0,0, (BYTE *)dataDir, &d);
  1269.     RegCloseKey(key);
  1270.   }
  1271.   if(RegOpenKey(HKEY_CURRENT_USER, subkey, &key)==ERROR_SUCCESS){
  1272.     for(Treg *u=regVal; u<endA(regVal); u++){
  1273.       d=sizeof(int);
  1274.       RegQueryValueEx(key,u->s,0,0, (BYTE *)u->i, &d);
  1275.     }
  1276.     for(Tregs *v=regValS; v<endA(regValS); v++){
  1277.       d=v->n;
  1278.       RegQueryValueEx(key,v->s,0,0, (BYTE *)v->i, &d);
  1279.     }
  1280.     d=sizeof(accel);
  1281.     if(RegQueryValueExA(key,"keys",0,0, (BYTE *)accel, &d)==ERROR_SUCCESS){
  1282.       Naccel=d/sizeof(ACCEL);
  1283.     }
  1284.     RegCloseKey(key);
  1285.   }
  1286. }
  1287. //-----------------------------------------------------------------
  1288. //tournament result window procedure
  1289. BOOL CALLBACK ResultProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM lP)
  1290. {
  1291.   static const Tresize D[]={{101,R_right|R_bottom},
  1292.   {IDOK,R_top|R_bottom},{606,R_top|R_bottom},{566,R_top|R_bottom}};
  1293.   
  1294.   resize(resultPos,D,sizeA(D),hWnd,msg,lP);
  1295.  
  1296.   switch(msg){
  1297.   case WM_INITDIALOG:
  1298.     setDlgTexts(hWnd,16);
  1299.     return TRUE;
  1300.   case WM_COMMAND:
  1301.     wP=LOWORD(wP);
  1302.     if(wP==566){
  1303.       copyToClipboard(GetDlgItem(hWnd,101));
  1304.       SetFocus(GetDlgItem(hWnd,IDOK));
  1305.     }
  1306.     if(wP==606){
  1307.       TfileName fn;
  1308.       strcpy(getTurDir(fn),fnHtmlTable);
  1309.       ShellExecute(hWin,"open",fn,0,0,SW_SHOWNORMAL);
  1310.     }
  1311.     if(wP==IDOK || wP==IDCANCEL) ShowWindow(hWnd,SW_HIDE);
  1312.     break;
  1313.   }
  1314.   return FALSE;
  1315. }
  1316. //-----------------------------------------------------------------
  1317. //log window procedure
  1318. BOOL CALLBACK LogProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM lP)
  1319. {
  1320.   static const Tresize D[]={{101,R_right|R_bottom},
  1321.   {4,R_top|R_bottom},{8,R_top|R_bottom},{566,R_top|R_bottom}};
  1322.   
  1323.   resize(logPos,D,sizeA(D),hWnd,msg,lP);
  1324.  
  1325.   switch(msg){
  1326.   case WM_INITDIALOG:
  1327.     setDlgTexts(hWnd,18);
  1328.     logWnd=GetDlgItem(hWnd,101);
  1329.     SendMessage(logWnd,EM_LIMITTEXT,0,0);
  1330.     return TRUE;
  1331.   case WM_COMMAND:
  1332.     wP=LOWORD(wP);
  1333.     if(wP==566){
  1334.       copyToClipboard(logWnd);
  1335.       SetFocus(GetDlgItem(hWnd,IDOK));
  1336.     }
  1337.     if(wP==8){
  1338.       SetWindowText(logWnd,"");
  1339.       SetFocus(GetDlgItem(hWnd,IDOK));
  1340.     }
  1341.     if(wP==4 || wP==IDCANCEL) ShowWindow(hWnd,SW_HIDE);
  1342.     if(wP==4 && turTimerAvail){
  1343.       SetTimer(hWin,997,10,0);
  1344.     }
  1345.     break;
  1346.   }
  1347.   return FALSE;
  1348. }
  1349. //-----------------------------------------------------------------
  1350. //options dialog procedure
  1351. BOOL CALLBACK OptionsProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1352. {
  1353.  int i,id;
  1354.  static int width1,height1,tolerance1,maxMemory1,exactFive1,continuous1;
  1355.  static struct{ int *prom,id; } D[]={
  1356.   {&width,103},
  1357.   {&height,104},
  1358.   {&hiliteDelay,108},
  1359.   {&tolerance,109},
  1360.   {&maxMemory,111},
  1361.   {&coordVisible,510},
  1362.   {&hardTimeOut,515},
  1363.   {&moveDiv2,516},
  1364.   {&moveStart,546},
  1365.   {&humanTimeOut,517},
  1366.   {&coordStart,518},
  1367.   {&logMessage,540},
  1368.   {&logDebug,541},
  1369.   {&logMoves,542},
  1370.   {&suspendAI,544},
  1371.   {&debugAI,658},
  1372.   {&autoBegin,545},
  1373.   {&infoEval,548},
  1374.   {&debugPipe,549},
  1375.   {&clearLog,509},
  1376.   {&ignoreErrors,659},
  1377.  };
  1378.  
  1379.  switch(msg){
  1380.   case WM_INITDIALOG:
  1381.    setDlgTexts(hWnd,12);
  1382.    width1=width;
  1383.    height1=height;
  1384.    tolerance1=tolerance;
  1385.    maxMemory1=maxMemory;
  1386.    exactFive1=exactFive;
  1387.    continuous1=continuous;
  1388.    for(i=0; i<sizeof(D)/sizeof(*D); i++){
  1389.      id=D[i].id;
  1390.      if(id>=100)
  1391.       if(id<300){
  1392.        SetDlgItemInt(hWnd,id, *D[i].prom, FALSE);
  1393.       }else{
  1394.        CheckDlgButton(hWnd,id, *D[i].prom ? BST_CHECKED:BST_UNCHECKED);
  1395.       }
  1396.    }
  1397.    CheckRadioButton(hWnd,555,556,555+exactFive);
  1398.    CheckRadioButton(hWnd,559,560,559+continuous);
  1399.    for(i=0; i<sizeA(priorTab); i++){
  1400.      SendDlgItemMessage(hWnd,120,CB_ADDSTRING,0,(LPARAM)lng(690+i,priorTab[i]));
  1401.    }
  1402.    SendDlgItemMessage(hWnd,120,CB_SETCURSEL,priority,0);
  1403.    SetDlgItemText(hWnd,122,dataDir);
  1404.    PostMessage(hWnd,WM_COMMAND,544,0);
  1405.    return TRUE;
  1406.  
  1407.   case WM_COMMAND:
  1408.    wP=LOWORD(wP);
  1409.    switch(wP){
  1410.     case 124:
  1411.      browseFolder(dataDir,hWnd,122,lng(558,"Folder for AI data files"));
  1412.      break;
  1413.     case 544: //suspend pbrain
  1414.      EnableWindow(GetDlgItem(hWnd,658),IsDlgButtonChecked(hWnd,544));
  1415.      break;
  1416.     case IDOK:
  1417.      for(i=0; i<sizeof(D)/sizeof(*D); i++){
  1418.        id=D[i].id;
  1419.        if(id>=100)
  1420.         if(id<200){
  1421.          *D[i].prom= GetDlgItemInt(hWnd,id, NULL, FALSE);
  1422.         }else{
  1423.          *D[i].prom= IsDlgButtonChecked(hWnd,id);
  1424.         }
  1425.      }
  1426.      exactFive= getRadioButton(hWnd,555,556);
  1427.      continuous= getRadioButton(hWnd,559,560);
  1428.      priority= (int) SendMessage(GetDlgItem(hWnd,120),CB_GETCURSEL,0,0);
  1429.      if(isWin9X){
  1430.        if(priority==1) priority=0;
  1431.        if(priority==3) priority=4;
  1432.      }
  1433.      setPriority(players[0].process);
  1434.      setPriority(players[1].process);
  1435.      GetDlgItemText(hWnd,122,dataDir,sizeof(dataDir));
  1436.      if(turNplayers || isNetGame){
  1437.        width=width1, height=height1, tolerance=tolerance1;
  1438.        exactFive=exactFive1, continuous=continuous1;
  1439.      }
  1440.      if(width1!=width || height1!=height){
  1441.        wP=119;
  1442.      }else{
  1443.        if(maxMemory1!=maxMemory){
  1444.          players[0].sendInfo(INFO_MEMORY);
  1445.          players[1].sendInfo(INFO_MEMORY);
  1446.        }
  1447.        if(exactFive1!=exactFive || continuous1!=continuous){
  1448.          players[0].sendInfo(INFO_RULE);
  1449.          players[1].sendInfo(INFO_RULE);
  1450.        }
  1451.        invalidate();
  1452.      }
  1453.     case IDCANCEL:
  1454.      EndDialog(hWnd, wP);
  1455.    }
  1456.   break;
  1457.  }
  1458.  return FALSE;
  1459. }
  1460. //-----------------------------------------------------------------
  1461. //players dialog procedure
  1462. BOOL CALLBACK PlayersProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1463. {
  1464.  Tplayer *p;
  1465.  BOOL e;
  1466.  int k;
  1467.  static int oldComp[2];
  1468.  static char oldBrain[2][_MAX_PATH];
  1469.  static int oldTime[2];
  1470.  static int oldTimeGame[2];
  1471.  
  1472.  switch(msg){
  1473.  
  1474.   case WM_INITDIALOG:
  1475.    setDlgTexts(hWnd,14);
  1476.    for(k=0; k<2; k++){
  1477.      p= &players[k];
  1478.      oldComp[k]= p->isComp;
  1479.      oldTime[k]= p->timeMove;
  1480.      oldTimeGame[k]= p->timeGame;
  1481.      strcpy(oldBrain[k],p->brain);
  1482.      SetDlgItemText(hWnd,101+k, p->brain);
  1483.      setDlgItemMs(hWnd,103+k, p->timeMove);
  1484.      SetDlgItemInt(hWnd,105+k, p->timeGame, FALSE);
  1485.    }
  1486.    CheckRadioButton(hWnd,522,523, 523-players[0].isComp);
  1487.    CheckRadioButton(hWnd,524,525, 525-players[1].isComp);
  1488.    CheckDlgButton(hWnd,530, sameTime ? BST_CHECKED:BST_UNCHECKED);
  1489.    PostMessage(hWnd,WM_COMMAND,530,0);
  1490.    PostMessage(hWnd,WM_COMMAND,522,0);
  1491.    PostMessage(hWnd,WM_COMMAND,524,0);
  1492.    return TRUE;
  1493.  
  1494.   case WM_COMMAND:
  1495.    wP=LOWORD(wP);
  1496.    switch(wP){
  1497.     case 530: //same times for both players
  1498.       e= !IsDlgButtonChecked(hWnd,530);
  1499.       EnableWindow(GetDlgItem(hWnd,104),e);
  1500.       EnableWindow(GetDlgItem(hWnd,106),e);
  1501.     break;
  1502.     case 522: case 523: //computer/human
  1503.       EnableWindow(GetDlgItem(hWnd,101),IsDlgButtonChecked(hWnd,522));
  1504.     break;
  1505.     case 524: case 525: //computer/human
  1506.       EnableWindow(GetDlgItem(hWnd,102),IsDlgButtonChecked(hWnd,524));
  1507.     break;
  1508.     case 200: case 201: //find AI on disk
  1509.      softPause();
  1510.      brainOfn.hwndOwner= hWnd;
  1511.      brainOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY;
  1512.      if(GetOpenFileName(&brainOfn)){
  1513.        SetDlgItemText(hWnd,wP-99,brainOfn.lpstrFile);
  1514.      }
  1515.     break;
  1516.     case IDOK:
  1517.      sameTime= IsDlgButtonChecked(hWnd,530);
  1518.      for(k=0; k<2; k++){
  1519.        p= &players[k];
  1520.        p->timeMove= getDlgItemMs(hWnd,103+k);
  1521.        p->timeGame= GetDlgItemInt(hWnd,105+k, NULL, FALSE);
  1522.        if(sameTime && k==1){
  1523.          p->timeMove=players[0].timeMove;
  1524.          p->timeGame=players[0].timeGame;
  1525.        }
  1526.        p->isComp= 1-getRadioButton(hWnd,522+2*k,523+2*k);
  1527.        if(p->isComp!=oldComp[k]){
  1528.          killBrains();
  1529.          resetScore();
  1530.        }
  1531.        GetDlgItemText(hWnd,101+k, p->brain, sizeof(p->brain));
  1532.        if(stricmp(p->brain,oldBrain[k])){
  1533.          killBrains();
  1534.          p->brainChanged();
  1535.          resetScore();
  1536.        }
  1537.        if(p->timeMove!=oldTime[k]){
  1538.          p->sendInfo(INFO_TIMEMOVE);
  1539.          levelChanged=true;
  1540.          printLevel();
  1541.        }
  1542.        if(p->timeGame!=oldTimeGame[k]){
  1543.          p->sendInfo(INFO_TIMEGAME|INFO_TIMELEFT);
  1544.          levelChanged=true;
  1545.        }
  1546.      }
  1547.     case IDCANCEL:
  1548.      EndDialog(hWnd, wP);
  1549.      break;
  1550.    }
  1551.   break;
  1552.  }
  1553.  return FALSE;
  1554. }
  1555. //-----------------------------------------------------------------
  1556. BOOL CALLBACK moveProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1557. {
  1558.   int i;
  1559.  
  1560.   switch(msg){
  1561.   case WM_INITDIALOG:
  1562.     setDlgTexts(hWnd,17);
  1563.     SetDlgItemInt(hWnd,101, gotoMove, FALSE);
  1564.     return TRUE;
  1565.   case WM_COMMAND:
  1566.     wP=LOWORD(wP);
  1567.     switch(wP){
  1568.     case IDOK:
  1569.       gotoMove= GetDlgItemInt(hWnd,101, NULL, FALSE);
  1570.       i= gotoMove-moveStart;
  1571.       if(moveDiv2) i*=2;
  1572.       while(moves<i && redo()) ;
  1573.       while(moves>i && undo()) ;
  1574.     case IDCANCEL:
  1575.       EndDialog(hWnd, wP);
  1576.       break;
  1577.     }
  1578.     break;
  1579.   }
  1580.   return FALSE;
  1581. }
  1582. //-----------------------------------------------------------------
  1583. BOOL CALLBACK msgProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM lP)
  1584. {
  1585.   static const Tresize D[]={{101,R_right|R_bottom},
  1586.   {9,R_top|R_bottom},{IDCANCEL,R_top|R_bottom}};
  1587.   
  1588.   resize(msgPos,D,sizeA(D),hWnd,msg,lP);
  1589.  
  1590.   switch(msg){
  1591.   case WM_INITDIALOG:
  1592.     setDlgTexts(hWnd,24);
  1593.     msgWnd=GetDlgItem(hWnd,101);
  1594.     return TRUE;
  1595.   case WM_COMMAND:
  1596.     wP=LOWORD(wP);
  1597.     switch(wP){
  1598.     case 9:
  1599.       if(isNetGame) netGameMsg();
  1600.       break;
  1601.     case IDCANCEL:
  1602.       ShowWindow(hWnd,SW_HIDE);
  1603.       break;
  1604.     }
  1605.     break;
  1606.   }
  1607.   return FALSE;
  1608. }
  1609. //---------------------------------------------------------------
  1610. BOOL CALLBACK clientProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1611. {
  1612.  BOOL e;
  1613.  
  1614.  switch(msg){
  1615.   case WM_INITDIALOG:
  1616.    setDlgTexts(hWnd,19);
  1617.    SetDlgItemText(hWnd,101, servername);
  1618.    SetDlgItemInt(hWnd,110, port, FALSE);
  1619.    SetDlgItemText(hWnd,103, AIfolder);
  1620.    CheckRadioButton(hWnd,597,598,597+whoConnect);
  1621.    PostMessage(hWnd,WM_COMMAND,597,0);
  1622.    return 1;
  1623.  
  1624.   case WM_COMMAND:
  1625.    wP=LOWORD(wP);
  1626.    switch(wP){
  1627.     case 107: //folder
  1628.       browseFolder(AIfolder,hWnd,103,lng(590,"Folder for AI:"));
  1629.     break;
  1630.     case 597: case 598:
  1631.       e= IsDlgButtonChecked(hWnd,597);
  1632.       EnableWindow(GetDlgItem(hWnd,103),e);
  1633.     break;
  1634.     case IDOK:
  1635.      if(!checkDir(hWnd,103)) break;
  1636.      GetDlgItemText(hWnd,101, servername, sizeof(servername));
  1637.      port= GetDlgItemInt(hWnd,110, NULL, FALSE);
  1638.      GetDlgItemText(hWnd,103, AIfolder, sizeof(AIfolder));
  1639.      whoConnect= getRadioButton(hWnd,597,598);
  1640.      if(whoConnect ? netGameStart() : clientStart()){ 
  1641.        SetFocus(GetDlgItem(hWnd,101)); 
  1642.        break; 
  1643.      }
  1644.     case IDCANCEL:
  1645.      EndDialog(hWnd, wP);
  1646.      break;
  1647.    }
  1648.   break;
  1649.  }
  1650.  return 0;
  1651. }
  1652. //-----------------------------------------------------------------
  1653. BOOL CALLBACK disconnectProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1654. {
  1655.  
  1656.  switch(msg){
  1657.  
  1658.   case WM_INITDIALOG:
  1659.    setDlgTexts(hWnd,23);
  1660.    CheckRadioButton(hWnd,595,596, 595);
  1661.    return TRUE;
  1662.  
  1663.   case WM_COMMAND:
  1664.    wP=LOWORD(wP);
  1665.    switch(wP){
  1666.     case 596:
  1667.      SetFocus(GetDlgItem(hWnd,101));
  1668.     break;
  1669.     case IDOK:
  1670.      if(getRadioButton(hWnd,595,596)){
  1671.        killClient(GetDlgItemInt(hWnd,101, NULL, FALSE));
  1672.      }else{
  1673.        serverEnd();
  1674.      }
  1675.     case IDCANCEL:
  1676.      EndDialog(hWnd, wP);
  1677.      break;
  1678.    }
  1679.   break;
  1680.  }
  1681.  return FALSE;
  1682. }
  1683. //-----------------------------------------------------------------
  1684. void turAddAI(bool noPath)
  1685. {
  1686.   char *s,*d,*path;
  1687.   int i,j;
  1688.  
  1689.   d=strchr(turPlayerStr,0);
  1690.   if(d>turPlayerStr && d[-1]!='\n'){ *d++='\r'; *d++='\n'; }
  1691.   path=brainOfn.lpstrFile;
  1692.   i=(int)strlen(path);
  1693.   s= path+i+1;
  1694.   if(!*s){
  1695.     //one file
  1696.     if(noPath) path=cutPath(path);
  1697.     strncpy(d,path,sizeof(turPlayerStr)-(d-turPlayerStr)-1);
  1698.   }else{
  1699.     //multiple files
  1700.     for(; *s; s++){
  1701.       j=(int)strlen(s);
  1702.       if((d-turPlayerStr)+i+j+4>sizeof(turPlayerStr)) break;
  1703.       if(!noPath){
  1704.         strcpy(d,path);
  1705.         d+=i;
  1706.         *d++='\\';
  1707.       }
  1708.       strcpy(d,s);
  1709.       d+=j;
  1710.       *d++='\r';
  1711.       *d++='\n';
  1712.       s+=j;
  1713.     }
  1714.     *d=0;
  1715.   }
  1716. }
  1717.  
  1718. BOOL CALLBACK TurProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  1719. {
  1720.  BOOL e;
  1721.  int i,id;
  1722.  FILE *f;
  1723.  static struct{ int *prom,id; } D[]={
  1724.   {&turRepeat,102},
  1725.   {&turMatchRepeat,115},
  1726.   {&players[0].timeMove,153},
  1727.   {&players[0].timeGame,105},
  1728.   {&turDelay,158},
  1729.   {&tolerance,109},
  1730.   {&maxMemory,111},
  1731.   {&turTieRepeat,112},
  1732.   {&turRecord,565},
  1733.   {&turOnlyLosses,573},
  1734.   {&port,110},
  1735.   {&autoBegin,545},
  1736.   {&turLogMsg,567},
  1737.  };
  1738.  
  1739.  switch(msg){
  1740.  
  1741.   case WM_INITDIALOG:
  1742.    setDlgTexts(hWnd,15);
  1743.    SetDlgItemText(hWnd,101, turPlayerStr);
  1744.    SetDlgItemText(hWnd,106, fntur);
  1745.    SetDlgItemText(hWnd,113, cmdGameEnd);
  1746.    SetDlgItemText(hWnd,114, cmdTurEnd);
  1747.    CheckRadioButton(hWnd,570,571, 570+turRule);
  1748.    CheckRadioButton(hWnd,575,576, 575+turNet);
  1749.    CheckDlgButton(hWnd,572, turFormat==2 ? BST_CHECKED:BST_UNCHECKED);
  1750.    for(i=0; i<sizeof(D)/sizeof(*D); i++){
  1751.      id=D[i].id;
  1752.      if(id>=100)
  1753.       if(id<300){
  1754.         if(id<150){
  1755.           SetDlgItemInt(hWnd,id, *D[i].prom, FALSE);
  1756.         }else{
  1757.           setDlgItemMs(hWnd,id, *D[i].prom);
  1758.         }
  1759.       }else{
  1760.         CheckDlgButton(hWnd,id, *D[i].prom ? BST_CHECKED:BST_UNCHECKED);
  1761.       }
  1762.    }
  1763.    PostMessage(hWnd,WM_COMMAND,565,0);
  1764.    PostMessage(hWnd,WM_COMMAND,576,0);
  1765.    return 1;
  1766.  
  1767.   case WM_COMMAND:
  1768.    wP=LOWORD(wP);
  1769.    switch(wP){
  1770.     case 564: //find AI on disk
  1771.       brainOfn.hwndOwner= hWnd;
  1772.       brainOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY|OFN_ALLOWMULTISELECT|OFN_EXPLORER;
  1773.       *brainOfn.lpstrFile=0;
  1774.       if(GetOpenFileName(&brainOfn)){
  1775.         GetDlgItemText(hWnd,101, turPlayerStr, sizeof(turPlayerStr)-2);
  1776.         turAddAI(false);
  1777.         SetDlgItemText(hWnd,101, turPlayerStr);
  1778.       }
  1779.     break;
  1780.     case 565: //save games to
  1781.       e= (BOOL)IsDlgButtonChecked(hWnd,565);
  1782.       EnableWindow(GetDlgItem(hWnd,572),e);
  1783.       EnableWindow(GetDlgItem(hWnd,573),e);
  1784.     break;
  1785.     case 575: //local
  1786.     case 576: //network
  1787.       EnableWindow(GetDlgItem(hWnd,110),IsDlgButtonChecked(hWnd,576));
  1788.     break;
  1789.     case 107: //folder
  1790.       browseFolder(fntur,hWnd,106,lng(565,"Save games to folder:"));
  1791.     break;
  1792.     case 569: //open
  1793.       if(!checkDir(hWnd,106)) break;
  1794.       GetDlgItemText(hWnd,106, fntur, sizeof(fntur));
  1795.       strcpy(getTurDir(fnstate),fnState);
  1796.       f=fopen(fnstate,"rb");
  1797.       if(f){
  1798.         fclose(f);
  1799.       }else{
  1800.         stateOfn.hwndOwner= hWnd;
  1801.         stateOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY|OFN_EXPLORER;
  1802.         stateOfn.lpstrInitialDir=fntur;
  1803.         *stateOfn.lpstrFile=0;
  1804.         if(!GetOpenFileName(&stateOfn)) break;
  1805.       }
  1806.     //!
  1807.     case IDOK:
  1808.      if(!checkDir(hWnd,106)) break;
  1809.      GetDlgItemText(hWnd,101, turPlayerStr, sizeof(turPlayerStr));
  1810.      GetDlgItemText(hWnd,106, fntur, sizeof(fntur));
  1811.      GetDlgItemText(hWnd,113, cmdGameEnd, sizeof(cmdGameEnd));
  1812.      GetDlgItemText(hWnd,114, cmdTurEnd, sizeof(cmdTurEnd));
  1813.      turRule= getRadioButton(hWnd,570,571);
  1814.      turNet= getRadioButton(hWnd,575,576);
  1815.      turFormat= 1+IsDlgButtonChecked(hWnd,572);
  1816.      for(i=0; i<sizeof(D)/sizeof(*D); i++){
  1817.        id=D[i].id;
  1818.        if(id>=100)
  1819.         if(id<300){
  1820.           *D[i].prom= (id<150)? GetDlgItemInt(hWnd,id, NULL, FALSE): getDlgItemMs(hWnd,id);
  1821.         }else{
  1822.           *D[i].prom= IsDlgButtonChecked(hWnd,id);
  1823.         }
  1824.      }
  1825.     case IDCANCEL:
  1826.      EndDialog(hWnd, wP);
  1827.      break;
  1828.    }
  1829.   break;
  1830.  }
  1831.  return FALSE;
  1832. }
  1833. //-----------------------------------------------------------------
  1834. void reloadMenu()
  1835. {
  1836.   static int subId[]={456,455,454,453,452,450,451};
  1837.   loadMenu(hWin,"MAINMENU",subId);
  1838.   checkMenus();        
  1839.   DrawMenuBar(hWin);
  1840. }
  1841.  
  1842. void accelChanged()
  1843. {
  1844.   DestroyAcceleratorTable(haccel);
  1845.   if(Naccel>0){
  1846.     haccel= CreateAcceleratorTable(accel,Naccel);
  1847.   }else{
  1848.     haccel= LoadAccelerators(inst, MAKEINTRESOURCE(3));
  1849.     Naccel= CopyAcceleratorTable(haccel,accel,sizeA(accel));
  1850.   }
  1851. }
  1852.  
  1853. void getCmdName(char *buf, int n, int cmd)
  1854. {
  1855.   char *s,*d;
  1856.  
  1857.   s=lng(cmd,0);
  1858.   if(s){
  1859.     lstrcpyn(buf,s,n);
  1860.   }else{
  1861.     MENUITEMINFO mii;
  1862.     mii.cbSize=sizeof(MENUITEMINFO);
  1863.     mii.fMask=MIIM_TYPE;
  1864.     mii.dwTypeData=buf;
  1865.     mii.cch= n;
  1866.     GetMenuItemInfo(GetMenu(hWin),cmd,FALSE,&mii);
  1867.   }
  1868.   for(s=d=buf; *s; s++){
  1869.     if(*s=='\t') *s=0;
  1870.     if(*s!='&') *d++=*s;
  1871.   }
  1872.   *d=0;
  1873. }
  1874.  
  1875. void changeKey(HWND hDlg, UINT vkey)
  1876. {
  1877.   char buf[64];
  1878.   BYTE flg;
  1879.   ACCEL *a,*e;
  1880.   
  1881.   dlgKey.key=(USHORT)vkey;
  1882.   //read shift states
  1883.   flg=FVIRTKEY|FNOINVERT;
  1884.   if(GetKeyState(VK_CONTROL)<0) flg|=FCONTROL;
  1885.   if(GetKeyState(VK_SHIFT)<0) flg|=FSHIFT;
  1886.   if(GetKeyState(VK_MENU)<0) flg|=FALT;
  1887.   dlgKey.fVirt=flg;
  1888.   //set hotkey edit control
  1889.   printKey(buf,&dlgKey);
  1890.   SetWindowText(GetDlgItem(hDlg,131),buf);
  1891.   //modify accelerator table
  1892.   e=accel+Naccel;
  1893.   if(!dlgKey.cmd){
  1894.     for(a=accel; a<e; a++){
  1895.       if(a->key==vkey && a->fVirt==flg){
  1896.         PostMessage(hDlg,WM_COMMAND,a->cmd,0);
  1897.       }
  1898.     }
  1899.   }else{
  1900.     for(a=accel; ; a++){
  1901.       if(a==e){
  1902.         *a=dlgKey;
  1903.         Naccel++;
  1904.         break;
  1905.       }
  1906.       if(a->cmd==dlgKey.cmd){
  1907.         a->fVirt=dlgKey.fVirt;
  1908.         a->key=dlgKey.key;
  1909.         if(vkey==0){
  1910.           memcpy(a,a+1,(e-a-1)*sizeof(ACCEL));
  1911.           Naccel--;
  1912.         }
  1913.         break;
  1914.       }
  1915.     }
  1916.     accelChanged();
  1917.     //change the main menu
  1918.     reloadMenu();
  1919.   }
  1920. }
  1921.  
  1922. static WNDPROC editWndProc;
  1923.  
  1924. //window procedure for hotkey edit control
  1925. LRESULT CALLBACK hotKeyClassProc(HWND hWnd, UINT mesg, WPARAM wP, LPARAM lP)
  1926. {
  1927.   switch(mesg){
  1928.   case WM_KEYDOWN:
  1929.   case WM_SYSKEYDOWN:
  1930.     if(wP!=VK_CONTROL && wP!=VK_SHIFT && wP!=VK_MENU && wP!=VK_RWIN && wP!=VK_LWIN){
  1931.       if((wP==VK_BACK || wP==VK_DELETE) && dlgKey.key) wP=0;
  1932.       changeKey(GetParent(hWnd),(UINT)wP);
  1933.       return 0;
  1934.     }
  1935.     break;
  1936.   case WM_CHAR:
  1937.     return 0; //don't write character to the edit control
  1938.   }
  1939.   return CallWindowProc((WNDPROC)editWndProc, hWnd, mesg, wP, lP);
  1940. }
  1941.  
  1942. LRESULT CALLBACK KeysDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM )
  1943. {
  1944.   static const int Mbuf=64;
  1945.   char buf[Mbuf];
  1946.   int i,n;
  1947.  
  1948.   switch (message){
  1949.   case WM_INITDIALOG:
  1950.     editWndProc = (WNDPROC) SetWindowLong(GetDlgItem(hWnd,131),
  1951.       GWL_WNDPROC, (LONG) hotKeyClassProc);
  1952.     setDlgTexts(hWnd,25);
  1953.     dlgKey.cmd=0;
  1954.     return TRUE;
  1955.  
  1956.   case WM_COMMAND:
  1957.    wParam=LOWORD(wParam);
  1958.    switch(wParam){
  1959.    default:
  1960.      //popup menu item
  1961.      if(wParam<500 && wParam>=100 && wParam!=131 && wParam!=172){
  1962.        //set command text
  1963.        dlgKey.cmd=(USHORT)wParam;
  1964.        getCmdName(buf,Mbuf,wParam);
  1965.        SetDlgItemText(hWnd,172,buf);
  1966.        HWND hHotKey=GetDlgItem(hWnd,131);
  1967.        if(!*buf) dlgKey.cmd=0; 
  1968.        else SetFocus(hHotKey);
  1969.        //change accelerator table
  1970.        dlgKey.key=0;
  1971.        *buf=0;
  1972.        for(ACCEL *a=accel+Naccel-1; a>=accel; a--){
  1973.          if(a->cmd==dlgKey.cmd){
  1974.            dlgKey.fVirt=a->fVirt;
  1975.            dlgKey.key=a->key;
  1976.            printKey(buf,&dlgKey);
  1977.            break;
  1978.          }
  1979.        }
  1980.        //set hotkey edit control
  1981.        SetWindowText(hHotKey,buf);
  1982.      }
  1983.      break;
  1984.    case 130:
  1985.      {
  1986.      RECT rc;
  1987.      GetWindowRect(GetDlgItem(hWnd,130),&rc);
  1988.      //create popup menu from the main menu
  1989.      HMENU hMenu= CreatePopupMenu();
  1990.      MENUITEMINFO mii;
  1991.      n=GetMenuItemCount(GetMenu(hWin));
  1992.      for(i=0; i<n; i++){
  1993.        mii.cbSize=sizeof(mii);
  1994.        mii.fMask=MIIM_SUBMENU|MIIM_TYPE;
  1995.        mii.cch=Mbuf;
  1996.        mii.dwTypeData=buf;
  1997.        GetMenuItemInfo(GetMenu(hWin),i,TRUE,&mii);
  1998.        InsertMenuItem(hMenu,0xffffffff,TRUE,&mii);
  1999.      }
  2000.      //show popup menu
  2001.      TrackPopupMenuEx(hMenu,
  2002.        TPM_RIGHTBUTTON, rc.left, rc.bottom, hWnd, NULL);
  2003.      //delete popup menu
  2004.      for(i=0; i<n; i++){
  2005.        RemoveMenu(hMenu,0,MF_BYPOSITION);
  2006.      }
  2007.      DestroyMenu(hMenu);
  2008.      break;
  2009.      }
  2010.    case IDOK:
  2011.    case IDCANCEL:
  2012.      EndDialog(hWnd, wParam);
  2013.     return TRUE;
  2014.    }
  2015.   }
  2016.   return FALSE;
  2017. }
  2018. //-----------------------------------------------------------------
  2019. DWORD getVer()
  2020. {
  2021.  HRSRC r;
  2022.  HGLOBAL h;
  2023.  void *s;
  2024.  VS_FIXEDFILEINFO *v;
  2025.  UINT i;
  2026.  
  2027.  r=FindResource(0,(char*)VS_VERSION_INFO,RT_VERSION);
  2028.  h=LoadResource(0,r);
  2029.  s=LockResource(h);
  2030.  if(!s || !VerQueryValue(s,"\\",(void**)&v,&i)) return 0;
  2031.  return v->dwFileVersionMS;
  2032. }
  2033.  
  2034. BOOL CALLBACK AboutProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM )
  2035. {
  2036.  char buf[48];
  2037.  DWORD d;
  2038.  
  2039.  switch(msg){
  2040.   case WM_INITDIALOG:
  2041.    setDlgTexts(hWnd,11);
  2042.    d=getVer();
  2043.    sprintf(buf,"%d.%d",HIWORD(d),LOWORD(d));
  2044.    SetDlgItemText(hWnd,101,buf);
  2045.    return TRUE;
  2046.  
  2047.   case WM_COMMAND:
  2048.    wP=LOWORD(wP);
  2049.    switch(wP){
  2050.     case 502:
  2051.       GetDlgItemTextA(hWnd,wP,buf,sizeA(buf));
  2052.       ShellExecuteA(0,0,buf,0,0,SW_SHOWNORMAL);
  2053.     break;
  2054.     case IDOK:
  2055.     case IDCANCEL:
  2056.      EndDialog(hWnd, wP);
  2057.    }
  2058.   break;
  2059.  }
  2060.  return FALSE;
  2061. }
  2062. //-----------------------------------------------------------------
  2063. void drawTitle()
  2064. {
  2065.   title= lng(20,"Piskvork");
  2066.   if(isClient) title= lng(21,"Piskvork - client");
  2067.   if(isServer) title= lng(22,"Piskvork - server");
  2068.   SetWindowText(hWin,title);
  2069. }
  2070.  
  2071. void moveMsgWnd()
  2072. {
  2073.  int d;
  2074.  RECT rc,rcs;
  2075.  
  2076.  SystemParametersInfo(SPI_GETWORKAREA,0,&rcs,0);
  2077.  GetWindowRect(msgDlg,&rc);
  2078.  d=rc.bottom-rcs.bottom;
  2079.  amax(d,logPos.y);
  2080.  if(d>0){
  2081.    SetWindowPos(logDlg,0,logPos.x,logPos.y-=d,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  2082.    SetWindowPos(msgDlg,0,rc.left,rc.top-=d,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  2083.  }
  2084. }
  2085.  
  2086. void langChanged()
  2087. {
  2088.  reloadMenu();
  2089.  status();
  2090.  drawTitle();
  2091.  psqOfn.lpstrFilter=lng(801,"Saved positions (*.psq)\0*.psq\0Gomotur record (*.rec)\0*.rec\0All files\0*.*\0");
  2092.  skinOfn.lpstrFilter=lng(500,"Skins (*.bmp)\0*.bmp\0");
  2093.  brainOfn.lpstrFilter=lng(802,"Artifical inteligence (*.exe,*.zip)\0*.exe;*.com;*.bat;*.zip\0");
  2094.  stateOfn.lpstrFilter=lng(814,"Tournament state (*.tur)\0*.tur\0");
  2095.  //create dialog windows
  2096.  changeDialog(logDlg,logPos,"LOG",(DLGPROC)LogProc);
  2097.  changeDialog(resultDlg,resultPos,"RESULT",(DLGPROC)ResultProc);
  2098.  if(msgPos.y<0){
  2099.    RECT rc;
  2100.    GetWindowRect(logDlg,&rc);
  2101.    msgPos.x=rc.left;
  2102.    msgPos.y=rc.bottom;
  2103.  }
  2104.  changeDialog(msgDlg,msgPos,"MSG",(DLGPROC)msgProc,logDlg);
  2105. }
  2106.  
  2107. //-----------------------------------------------------------------
  2108. LRESULT CALLBACK MainWndProc(HWND hWnd, UINT mesg, WPARAM wP, LPARAM lP)
  2109. {
  2110.  static PAINTSTRUCT ps;
  2111.  RECT rcw;
  2112.  int i,x,y;
  2113.  int hr;
  2114.  bool a;
  2115.  Psquare p;
  2116.  
  2117.  hr=player;
  2118.  if(!players[hr].isComp && players[1-hr].isComp) hr=1-hr;
  2119.  
  2120.  switch (mesg) {
  2121.  case WM_COMMAND:
  2122.   wP=LOWORD(wP);
  2123.   if(setLang(wP)) break;
  2124.   switch(wP){
  2125.    case 120: //readme
  2126.    case 250: //what's new
  2127.    {
  2128.     char buf[256];
  2129.     getExeDir(buf, wP==250 ? lng(26,"WhatsNew.txt"):lng(13,"piskvork.txt"));
  2130.     if(ShellExecute(0,"open",buf,0,0,SW_SHOWNORMAL)==(HINSTANCE)ERROR_FILE_NOT_FOUND){
  2131.       msglng(739,"File %s not found",buf);
  2132.     }
  2133.    }
  2134.    break;
  2135.    case 121: //about
  2136.     DialogBox(inst, "ABOUT", hWnd, (DLGPROC) AboutProc);
  2137.    break;
  2138.    case 310:
  2139.      SendMessage(toolbar,TB_CUSTOMIZE,0,0);
  2140.      invalidate();
  2141.    break;
  2142.    case 103: //exit
  2143.     SendMessage(hWin,WM_CLOSE,0,0);
  2144.    break;
  2145.    case 105: //delete settings
  2146.      if(MessageBox(hWnd, lng(736,"Do you want to delete your settings ?"),
  2147.       title, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) ==IDYES){
  2148.        deleteini();
  2149.      }
  2150.    break;
  2151.    case 107: //save position
  2152.     savePsq();
  2153.    break;
  2154.    case 108: //ESC
  2155.     hardPause();
  2156.     if(turNplayers && !isClient){
  2157.       a=turTimerAvail;
  2158.       turTimerAvail=false;
  2159.       if(MessageBox(hWnd, lng(810,"Do you want to abort the tournament ?"),
  2160.         title, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) ==IDYES){
  2161.         if(a) KillTimer(hWnd,997);
  2162.         turAbort();
  2163.       }else{
  2164.         resume();
  2165.         turTimerAvail=a;
  2166.       }
  2167.     }
  2168.    break;
  2169.    case 209: //continue
  2170.     if(stopThinking()==0) resume();
  2171.    break;
  2172.    case 203: //show last move
  2173.     showLast();
  2174.    break;
  2175.    case 204: //delete score
  2176.     resetScore();
  2177.    break;
  2178.    case 207: //swap symbols
  2179.     invert= !invert;
  2180.     invalidate();
  2181.    break;
  2182.    case 221: //log window
  2183.     show(logDlg);
  2184.    break;
  2185.    case 224: //tournament result
  2186.     if(!isClient) show(resultDlg);
  2187.    break;
  2188.    case 301: //open skin
  2189.     openSkin();
  2190.    break;
  2191.    case 302: //next skin
  2192.     nextSkin();
  2193.    break;
  2194.    case 303: //previous skin
  2195.     prevSkin();
  2196.    break;
  2197.    case 304: //refresh skin
  2198.     loadSkin();
  2199.    break;
  2200.    case 305: //flip horizontally
  2201.     flipHoriz=!flipHoriz;
  2202.     invalidate();
  2203.    break;
  2204.    case 306: //flip vertically
  2205.     flipVert=!flipVert;
  2206.     invalidate();
  2207.    break;
  2208.    case 307: //flip diagonally
  2209.     flipDiag=!flipDiag;
  2210.     invalidate();
  2211.    break;
  2212.    case 104: //options
  2213.     if(!isServer || !turNplayers){
  2214.       if( DialogBox(inst,"OPTIONS",hWnd,(DLGPROC) OptionsProc)
  2215.         == 119){
  2216.         killBrains();
  2217.         newGame(player,true); 
  2218.       }
  2219.     }
  2220.    break;
  2221.    case 998: //write log
  2222.      if(lP){
  2223.        i=GetWindowTextLength(logWnd);
  2224.        SendMessage(logWnd,EM_SETSEL,i,i);
  2225.        SendMessage(logWnd,EM_REPLACESEL,FALSE,lP);
  2226.        delete[] (char*)lP;
  2227.      }else if(clearLog){
  2228.        SetWindowText(logWnd,"");
  2229.      }
  2230.    break;
  2231.    case 996: //result
  2232.      SetDlgItemText(resultDlg,101, lP ? (char*)lP : "");
  2233.      delete[] (char*)lP;
  2234.    break;
  2235.    case 995: //tie
  2236.      restartGame();
  2237.    break;
  2238.    case 994: //show log or result
  2239.      ShowWindow((HWND)lP,SW_SHOW);
  2240.      SetForegroundWindow((HWND)lP);
  2241.    break;
  2242.    case 992: //start network game
  2243.      if(isNetGame) newNetGame(lP);
  2244.    break;
  2245.    case 991: //network player's turn
  2246.      if(isNetGame && player==NET_PLAYER){
  2247.        doMove1((Psquare)lP,1);
  2248.        hiliteLast();
  2249.      }
  2250.    break;
  2251.    case 990: //network undo
  2252.      if(isNetGame){
  2253.        while(moves>undoRequest && undo()) ;
  2254.        undoRequest=0;
  2255.      }
  2256.    break;
  2257.    case 989: //network new game
  2258.      if(isNetGame){
  2259.        newGame(player,false);
  2260.        undoRequest=0;
  2261.      }
  2262.    break;
  2263.    case 219: //tournament button
  2264.      PostMessage(hWin,WM_COMMAND,turNplayers? 224:220,0);
  2265.    break;
  2266.    case 309: //show toolbar
  2267.      i = IsWindowVisible(toolbar);
  2268.      mtop=0;
  2269.      if(!i) mtop= toolBarH;
  2270.      ShowWindow(toolbar, i ? SW_HIDE:SW_SHOW);
  2271.      toolBarVisible = !i;
  2272.      invalidate();
  2273.      checkMenus();
  2274.    break;
  2275.    case 230:
  2276.      DialogBox(inst, "KEYS", hWin, (DLGPROC)KeysDlgProc);
  2277.    break;
  2278.    case 222: //disconnect
  2279.      clientEnd();
  2280.      netGameEnd();
  2281.      if(isServer){
  2282.        DialogBox(inst,"DISCONNECT",hWnd,(DLGPROC)disconnectProc);
  2283.      }
  2284.    break;
  2285.    case 227: //send text message to the other player 
  2286.     if(isNetGame){ 
  2287.       SetWindowText(msgWnd,"");
  2288.       moveMsgWnd();
  2289.       show(msgDlg);
  2290.       SetFocus(msgWnd);
  2291.     }else msglng(819,"Messages can be sent only between two players over the internet");
  2292.    break;                    
  2293.    case 101: //new game
  2294.      if(isNetGame){
  2295.        if(finished) newGame(player,false);
  2296.        else netGameNew();
  2297.      }
  2298.    break;                    
  2299.    case 201: //undo
  2300.    case 210:
  2301.      if(isNetGame) netGameUndo();
  2302.    break;
  2303.   }
  2304.  
  2305.   if(turNplayers || isNetGame) break;
  2306.  
  2307.   switch(wP){
  2308.    case 993: //resize to 20x20
  2309.      killBrains();
  2310.      width=height=20;
  2311.      newGame(whoStarted(),true);
  2312.      resume();
  2313.    break;
  2314.    case 220: //tournament
  2315.     i=DialogBox(inst,"TOURNAMENT",hWnd, (DLGPROC) TurProc);
  2316.     if(i==IDOK){
  2317.       writeini();
  2318.       turStart();
  2319.     }
  2320.     if(i==569){
  2321.       turRestart();
  2322.     }
  2323.    break;
  2324.    case 101: //new game
  2325.     newGame((moves<=startMoves+1 && (moves&1)==0 || moves==width*height) ? 1-player : player, true);
  2326.     resume();
  2327.    break;
  2328.    case 106: //open position
  2329.     killBrains();
  2330.     openPsq();
  2331.    break;
  2332.    case 404: //increment level
  2333.     setLevel(players[hr].level()+1, hr);
  2334.    break;
  2335.    case 405: //decrement level
  2336.     setLevel(players[hr].level()-1,hr);
  2337.    break;
  2338.    case 401: //human x human
  2339.     switchPlayer(0,0);
  2340.    break;
  2341.    case 402: //computer x human
  2342.     switchPlayer(1,0);
  2343.    break;
  2344.    case 403: //computer x computer
  2345.     switchPlayer(1,1);
  2346.    break;
  2347.    case 406: //players settings
  2348.     DialogBox(inst,"PLAYERS",hWnd,(DLGPROC) PlayersProc);
  2349.     printLevel();
  2350.    break;
  2351.    case 206: //swap players
  2352.     {
  2353.     killBrains();
  2354.     Tplayer w= players[0];
  2355.     players[0]=players[1];
  2356.     players[1]=w;
  2357.     int t=players[0].time;
  2358.     players[0].time=players[1].time;
  2359.     players[1].time=t;
  2360.     players[0].threads.init();
  2361.     players[1].threads.init();
  2362.     printScore();
  2363.     printLevel();
  2364.     resume();
  2365.     }
  2366.    break;
  2367.    case 210: //undo 2x
  2368.     if(moves>2){
  2369.       if(notSuspended()){
  2370.         hardPause();
  2371.       }else{
  2372.         hiliteLast();
  2373.         Sleep(min(hiliteDelay,40));
  2374.         undo();
  2375.       }
  2376.       hiliteLast();
  2377.       Sleep(min(hiliteDelay,150));
  2378.       undo();
  2379.     }
  2380.    break;
  2381.    case 201: //undo
  2382.     hardPause();
  2383.     hiliteLast();
  2384.     Sleep(min(hiliteDelay,70));
  2385.     undo();
  2386.    break;
  2387.   }
  2388.  
  2389.   if(notSuspended()) break;
  2390.  
  2391.   switch(wP){
  2392.    case 223: 
  2393.     if(!isServer) DialogBox(inst,"CLIENT",hWnd,(DLGPROC) clientProc);
  2394.    break;                                  
  2395.    case 202: //redo
  2396.     redo();
  2397.     hiliteLast();
  2398.    break;
  2399.    case 205: //undo all
  2400.     while(undo()) ;
  2401.    break;
  2402.    case 208: //redo all
  2403.     while(redo()) ;
  2404.    break;
  2405.    case 211: //redo 2x
  2406.     redo();
  2407.     hiliteLast();
  2408.     Sleep(min(hiliteDelay,250));
  2409.     redo();
  2410.     hiliteLast();
  2411.    break;
  2412.    case 212: //go to move
  2413.     DialogBox(inst, "GOTO", hWnd, (DLGPROC) moveProc);
  2414.    break;
  2415.   }
  2416.  break;
  2417.  
  2418.  case WM_RBUTTONDOWN:
  2419.   if(onAIName(1,lP)) switchPlayer(players[0].isComp,1-players[1].isComp);
  2420.   else if(onAIName(0,lP)) switchPlayer(1-players[0].isComp,players[1].isComp);
  2421.   else if(finished || moves==0){
  2422.     PostMessage(hWnd,WM_COMMAND,101,0);
  2423.   }else{
  2424.     showLast();
  2425.   }
  2426.  break;
  2427.  
  2428.  case WM_LBUTTONDBLCLK:
  2429.    if(turNplayers || isNetGame) break;
  2430.    for(i=0; i<2; i++){
  2431.     if(onAIName(i,lP)){
  2432.       softPause();
  2433.       brainOfn.hwndOwner= hWnd;
  2434.       brainOfn.Flags= OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_READONLY;
  2435.       if(GetOpenFileName(&brainOfn)){
  2436.         Tplayer *p= &players[i];
  2437.         if(stricmp(p->brain,brainOfn.lpstrFile) || !p->isComp){
  2438.           killBrains();
  2439.           strcpy(p->brain,brainOfn.lpstrFile);
  2440.           p->brainChanged();
  2441.           if(!p->isComp) p->isComp=1;
  2442.           printLevel();
  2443.           resume();
  2444.         }
  2445.       }   
  2446.       break;
  2447.     }
  2448.   }
  2449.  break;
  2450.  
  2451.  case WM_LBUTTONDOWN:
  2452.    if(notSuspended()) break;
  2453.    if(HIWORD(lP)<=heightb){
  2454.      if((!players[player].isComp || (wP & MK_CONTROL)) && 
  2455.        (player!=NET_PLAYER || !isNetGame) ){
  2456.        getMousePos(lP,x,y);
  2457.        if(players[player].isComp) boardChanged();
  2458.        if(moves==startMoves) lastTick=getTickCount();
  2459.        doMove1(Square(x,y));
  2460.      }
  2461.      resume();
  2462.    }
  2463.  break;
  2464.  
  2465.  case WM_MOUSEMOVE:
  2466.   getMousePos(lP,x,y);
  2467.   if(x!=mx || y!=my){
  2468.     mx=x; my=y;
  2469.     printMouseCoord();
  2470.     sendInfoEval();
  2471.   }
  2472.  break;
  2473.  
  2474.  case WM_TIMER:
  2475.   EnterCriticalSection(&timerLock);
  2476.   if(wP==10) cancelHilite();
  2477.   if(wP==102) printTime(player);
  2478.   if(wP==997 && turNplayers && turTimerAvail){
  2479.     turTimerAvail=false;
  2480.     KillTimer(hWnd,wP);
  2481.     turLocalNext();
  2482.   }
  2483.   LeaveCriticalSection(&timerLock);
  2484.  break;
  2485.  
  2486.  case WM_CHAR:
  2487.   if(isNetGame && wP>32){
  2488.     SendMessage(hWnd,WM_COMMAND,227,0);
  2489.     char c[2];
  2490.     c[0]=(char)wP; 
  2491.     c[1]=0;
  2492.     SendMessage(msgWnd,EM_REPLACESEL,TRUE,(LPARAM)c);
  2493.   }else if(wP>='0' && wP<='9') setLevel(wP-'0',hr); 
  2494.  break;
  2495.  
  2496.  case WM_KEYDOWN:
  2497.   if(wP==VK_ESCAPE) SendMessage(hWnd,WM_COMMAND,108,0);
  2498.  break;
  2499.  
  2500.  case WM_PAINT:
  2501.   BeginPaint(hWnd,&ps);
  2502.   repaint(&ps.rcPaint);
  2503.   EndPaint(hWnd, &ps);
  2504.  break;
  2505.  
  2506.  case WM_NOTIFY: 
  2507.    if(lP){                     
  2508.      NMTOOLBAR *nmtool;
  2509.      switch(((NMHDR*)lP)->code){
  2510.      case TBN_QUERYDELETE:
  2511.      case TBN_QUERYINSERT:
  2512.        return TRUE;
  2513.      case TBN_GETBUTTONINFO:
  2514.        nmtool= (NMTOOLBAR*) lP;
  2515.        i= nmtool->iItem;
  2516.        if(i<sizeA(tbb)){
  2517.          lstrcpyn(nmtool->pszText, lng(tbb[i].idCommand+1000,toolNames[i]), nmtool->cchText);
  2518.          nmtool->tbButton= tbb[i];
  2519.          return TRUE;
  2520.        }
  2521.        break;
  2522.      case TBN_RESET:
  2523.        while(SendMessage(toolbar,TB_DELETEBUTTON,0,0)) ;
  2524.        SendMessage(toolbar,TB_ADDBUTTONS,Ntool,(LPARAM)tbb);
  2525.        break;
  2526.      case TTN_NEEDTEXT:
  2527.        TOOLTIPTEXT *ttt= (LPTOOLTIPTEXT) lP;
  2528.        for(i=0; i<sizeA(tbb); i++){
  2529.          if(tbb[i].idCommand==(int)ttt->hdr.idFrom){
  2530.            ttt->hinst= NULL;
  2531.            ttt->lpszText= lng(ttt->hdr.idFrom+1000,toolNames[i]);
  2532.          }
  2533.        }
  2534.        break;
  2535.      }
  2536.    }
  2537.  break;
  2538.  
  2539.  case WM_MOVE:
  2540.   if(!IsZoomed(hWnd) && !IsIconic(hWnd)){
  2541.     GetWindowRect(hWnd,&rcw);
  2542.     mainPos.y= rcw.top;
  2543.     mainPos.x= rcw.left;
  2544.   }
  2545.  break;
  2546.  
  2547.  case WM_APP+123:
  2548.    p=Square(LOWORD(lP),HIWORD(lP));
  2549.    if(player && (wP==1 || wP==2)) wP^=3;
  2550.    if(p>=boardb && p<boardk) paintSquare(wP,p);
  2551.  break;
  2552.  
  2553.  case WM_QUERYENDSESSION:
  2554.   if(!delreg) writeini();
  2555.   return TRUE;
  2556.  
  2557.  case WM_CLOSE:
  2558.   if(!delreg) writeini();
  2559.   killBrains();
  2560.   serverEnd();
  2561.   clientEnd();
  2562.   netGameEnd();
  2563.   netGameEnd();
  2564.   DestroyWindow(logDlg);
  2565.   DestroyWindow(resultDlg);
  2566.   DestroyWindow(msgDlg);
  2567.   DestroyWindow(hWin);
  2568.   hWin=0;
  2569.  break;
  2570.  case WM_DESTROY:
  2571.   PostQuitMessage(0);
  2572.  break;
  2573.  
  2574.  default:
  2575.   return DefWindowProc(hWnd, mesg, wP, lP);
  2576. }
  2577. return 0;
  2578. }
  2579. //-----------------------------------------------------------------
  2580. int pascal WinMain(HINSTANCE hInstance,HINSTANCE hPrevInst,LPSTR cmdLine,int cmdShow)
  2581. {
  2582.  int i;
  2583.  WNDCLASS wc;
  2584.  MSG msg;
  2585.  OSVERSIONINFO v;
  2586.  
  2587.  v.dwOSVersionInfoSize= sizeof(OSVERSIONINFO);
  2588.  GetVersionEx(&v);
  2589.  isWin9X= v.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS;
  2590.  if(GetProcAddress(GetModuleHandle("comctl32.dll"),"DllGetVersion")){
  2591.    INITCOMMONCONTROLSEX iccs;
  2592.    iccs.dwSize= sizeof(INITCOMMONCONTROLSEX);
  2593.    iccs.dwICC= ICC_BAR_CLASSES;
  2594.    InitCommonControlsEx(&iccs);
  2595.  }else{
  2596.    InitCommonControls();
  2597.  }           
  2598.  inst=hInstance;
  2599.  //temporary file names for old AI interface
  2600.  GetTempPath(sizeof(tempDir),tempDir);
  2601.  sprintf(strchr(tempDir,0),"psqp%d\\",GetCurrentProcessId());
  2602.  sprintf(players[0].temp,"%sunz0\\",tempDir);
  2603.  sprintf(players[1].temp,"%sunz1\\",tempDir);
  2604.  sprintf(TahDat,"%sTah.dat",tempDir);
  2605.  sprintf(PlochaDat,"%sPlocha.dat",tempDir);
  2606.  sprintf(TimeOutsDat,"%sTimeOuts.dat",tempDir);
  2607.  sprintf(InfoDat,"%sInfo.dat",tempDir);
  2608.  sprintf(MsgDat,"%smsg.dat",tempDir);
  2609.  
  2610.  //read settings
  2611.  players[0].isComp=1;
  2612.  players[0].timeGame= 180;
  2613.  players[0].timeMove= 5000;
  2614.  players[1].timeGame= 600;
  2615.  players[1].timeMove= 60000;
  2616.  readini();
  2617.  initLang();
  2618.  //register window class
  2619.  wc.style= CS_OWNDC|CS_DBLCLKS;
  2620.  wc.lpfnWndProc= MainWndProc;
  2621.  wc.cbClsExtra= 0;
  2622.  wc.cbWndExtra= 0;
  2623.  wc.hInstance= hInstance;
  2624.  wc.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(1));
  2625.  wc.hCursor= LoadCursor(NULL, IDC_ARROW);
  2626.  wc.hbrBackground= NULL;
  2627.  wc.lpszMenuName= 0;
  2628.  wc.lpszClassName= "Piskvork";
  2629.  if(!hPrevInst && !RegisterClass(&wc)) return 11;
  2630.  //create main window
  2631.  int sw,sh;
  2632.  sw=GetSystemMetrics(SM_CXSCREEN);
  2633.  sh=GetSystemMetrics(SM_CYSCREEN);
  2634.  aminmax(mainPos.x,-5,sw-300);
  2635.  aminmax(mainPos.y,-5,sh-200);
  2636.  hWin = CreateWindow( "Piskvork", "",
  2637.    WS_OVERLAPPEDWINDOW-WS_THICKFRAME-WS_MAXIMIZEBOX, mainPos.x, mainPos.y,
  2638.    0, 0, NULL, NULL, hInstance, NULL);
  2639.  if(!hWin) return 12;
  2640.  dc= GetDC(hWin);
  2641.  //create toolbar
  2642.  int n=sizeA(tbb);
  2643.  for(i=0; i<sizeA(tbb); i++){
  2644.    if(tbb[i].fsStyle==TBSTYLE_SEP) n--;
  2645.  }
  2646.  toolbar = CreateToolbarEx(hWin,
  2647.    WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_FLAT, 1000, n,
  2648.    inst, 11, tbb, Ntool,
  2649.    16,16, 16,16, sizeof(TBBUTTON));
  2650.  TBSAVEPARAMS sp;
  2651.  sp.hkr=HKEY_CURRENT_USER;
  2652.  sp.pszSubKey=subkey;
  2653.  sp.pszValueName="toolbar";
  2654.  SendMessage(toolbar,TB_SAVERESTORE,FALSE,(LPARAM)&sp);
  2655.  if(toolBarVisible){
  2656.    ShowWindow(toolbar, SW_SHOW);
  2657.    UpdateWindow(toolbar);
  2658.    mtop=toolBarH;
  2659.  }
  2660.  //load skin
  2661.  bmpdc= CreateCompatibleDC(dc);
  2662.  loadSkin(LoadBitmap(hInstance, MAKEINTRESOURCE(10)));
  2663.  if(!*fnskin){
  2664.    getExeDir(fnskin,"skins\\");
  2665.  }else{
  2666.    loadSkin();
  2667.  }
  2668.  CreateDirectory(tempDir,0);
  2669.  accelChanged();
  2670.  langChanged();
  2671.  InitializeCriticalSection(&infoLock);
  2672.  InitializeCriticalSection(&timerLock);
  2673.  InitializeCriticalSection(&threadsLock);
  2674.  InitializeCriticalSection(&netLock);
  2675.  DWORD threadId;
  2676.  thread= CreateThread(0,0,threadLoop,0,CREATE_SUSPENDED,&threadId);
  2677.  players[0].brainChanged();
  2678.  players[1].brainChanged();
  2679.  for(i=0; i<Mplayer; i++){
  2680.    Tclient *c=&clients[i];
  2681.    c->socket=INVALID_SOCKET;
  2682.    c->thread=0;
  2683.    c->player[0]=-1;
  2684.  }
  2685.  ShowWindow(hWin, cmdShow);
  2686.  initOpeningTab();
  2687.  if(__argc==4){
  2688.    if(!strcmp(__argv[1],"-p")){
  2689.      cmdLineGame=true;
  2690.      strncpy(players[0].brain,__argv[2],sizeof(players[0].brain)-1);
  2691.      strncpy(players[1].brain,__argv[3],sizeof(players[0].brain)-1);
  2692.      players[0].isComp=players[1].isComp=1;
  2693.      players[0].brainChanged();
  2694.      players[1].brainChanged();
  2695.      newGame(0,true);
  2696.      resume();
  2697.    }
  2698.  }else{
  2699.    newGame(!players[1].isComp,false);
  2700.    openPsq(cmdLine);
  2701.  }
  2702.  
  2703.  while(GetMessage(&msg, NULL, 0, 0)==TRUE)
  2704.   if(msg.hwnd==msgWnd || !TranslateAccelerator(hWin,haccel,&msg)){
  2705.     if(!logDlg || !IsDialogMessage(logDlg,&msg))
  2706.     if(!msgDlg || !IsDialogMessage(msgDlg,&msg))
  2707.     if(!resultDlg || !IsDialogMessage(resultDlg,&msg)){
  2708.       TranslateMessage(&msg);
  2709.       DispatchMessage(&msg);
  2710.     }
  2711.   }
  2712.                         
  2713.  delDir(tempDir,true);
  2714.  FreeLibrary(psapi);
  2715.  DeleteDC(bmpdc);
  2716.  DeleteObject(bm);
  2717.  DestroyAcceleratorTable(haccel);
  2718.  shutOpeningTab();
  2719.  delete[] board;
  2720.  delete[] turTable;
  2721.  delete[] turCells;
  2722.  DeleteCriticalSection(&netLock);
  2723.  DeleteCriticalSection(&threadsLock);
  2724.  DeleteCriticalSection(&timerLock);
  2725.  DeleteCriticalSection(&infoLock);
  2726.  cleanTemp();
  2727.  return 0;
  2728. }
  2729. //-----------------------------------------------------------------
  2730.